Modifying a set during iteration java - java

I'm looking to make a recursive method iterative.
I have a list of Objects I want to iterate over, and then check their subobjects.
Recursive:
doFunction(Object)
while(iterator.hasNext())
{
//doStuff
doFunction(Object.subObjects);
}
I want to change it to something like this
doFunction(Object)
iIterator = hashSet.iterator();
while(Iterator.hasNext()
{
//doStuff
hashSet.addAll(Object.subObjects);
}
Sorry for the poor psuedo code, but basically I want to iterate over subobjects while appending new objects to the end of the list to check.
I could do this using a list, and do something like
while(list.size() > 0)
{
//doStuff
list.addAll(Object.subObjects);
}
But I would really like to not add duplicate subObjects.
Of course I could just check whether list.contains(each subObject) before I added It.
But I would love to use a Set to accomplish that cleaner.
So Basically is there anyway to append to a set while Iterating over it, or is there an easier way to make a List act like a set rather than manually checking .contains()?
Any comments are appreciated.
Thanks

I would use two data structures --- a queue (e.g. ArrayDeque) for storing objects whose subobjects are to be visited, and a set (e.g. HashSet) for storing all visited objects without duplication.
Set visited = new HashSet(); // all visited objects
Queue next = new ArrayDeque(); // objects whose subobjects are to be visited
// NOTE: At all times, the objects in "next" are contained in "visited"
// add the first object
visited.add(obj);
Object nextObject = obj;
while (nextObject != null)
{
// do stuff to nextObject
for (Object o : nextObject.subobjects)
{
boolean fresh = visited.add(o);
if (fresh)
{
next.add(o);
}
}
nextObject = next.poll(); // removes the next object to visit, null if empty
}
// Now, "visited" contains all the visited objects
NOTES:
ArrayDeque is a space-efficient queue. It is implemented as a cyclic array, which means you use less space than a List that keeps growing when you add elements.
"boolean fresh = visited.add(o)" combines "boolean fresh = !visited.contains(o)" and "if (fresh) visited.add(o)".

I think your problem is inherently a problem that needs to be solved via a List. If you think about it, your Set version of the solution is just converting the items into a List then operating on that.
Of course, List.contains() is a slow operation in comparison to Set.contains(), so it may be worth coming up with a hybrid if speed is a concern:
while(list.size() > 0)
{
//doStuff
for each subObject
{
if (!set.contains(subObject))
{
list.add(subObject);
set.add(subObject)
}
}
}
This solution is fast and also conceptually sound - the Set can be thought of as a list of all items seen, whereas the List is a queue of items to work on. It does take up more memory than using a List alone, though.

If you do not use a List, the iterator will throw an exception as soon as you read from it after modifying the set. I would recommend using a List and enforcing insertion limits, then using ListIterator as that will allow you to modify the list while iterating over it.

HashSet nextObjects = new HashSet();
HashSet currentObjects = new HashSet(firstObject.subObjects);
while(currentObjects.size() > 0)
{
Iterator iter = currentObjects.iterator();
while(iter.hasNext())
{
//doStuff
nextObjects.add(subobjects);
}
currentObjects = nextObjects;
nextObjects = new HashSet();
}
I think something like this will do what I want, I'm not concerned that the first Set contains duplicates, only that the subObjects may point to the same objects.

Use more than one set and do it in "rounds":
/* very pseudo-code */
doFunction(Object o) {
Set processed = new HashSet();
Set toProcess = new HashSet();
Set processNext = new HashSet();
toProcess.add(o);
while (toProcess.size() > 0) {
for(it = toProcess.iterator(); it.hasNext();) {
Object o = it.next();
doStuff(o);
processNext.addAll(o.subObjects);
}
processed.addAll(toProcess);
toProcess = processNext;
toProcess.removeAll(processed);
processNext = new HashSet();
}
}

Why not create an additional set that contains the entire set of objects? You can use that for lookups.

Related

Iterators in Java

So I have a list of integers for each object of a class.
I am trying to iterate over list of each object, when i encounter a certain condition I move on to the next object and so forth.
My question here is, when i get back to the pervious object which still has unvisited elements in the list how do I remember the iterator for that particular object. Here is the code I have written:
void function(Object u, List<Integer> tour, Iterator it) {
Object e;
while (it.hasNext()) {
e = it.next();
if (!e.visited) {
tour.add(e);
e.visited = true;
Vertex v = e.otherEnd(e.from);
v.outgoing++;
it = v.adj.listIterator(v.outgoing - 1);
//So instead of re-assigning Iterator it each time is there way //to remember the iterator for each list associated with the object?
}
}
Theres three approachs:
Use a for on a new iterator (but it will be only for the second level of your graph and repeated code)
The second one is to change it to recursive.
Or you can do something about having a Stack and be pushing/poping it when necessary.
Create a map to store the index each iterator has gotten to for an object. You can update the map when you need to switch to a new object and pull from it whenever you come back to it

How to keep iterating ArrayList as you remove objects from it

In hopes of trying to implement the Banker's algorithm in Java I am attempting to iterate through an ArrayList that stores the id of a number of threads. I want to keep iterating through this array until I have found a safe sequence (or not). So far, I am able to iterate through the ArrayList only once, but I need to remove objects as iterate if I found that they are next in my safe sequence.
How do I keep iterating through an ArrayList (or any other data structure) in a circular fashion as I remove objects from it as I go? I hope my question is clear enough, but here is what I have so far:
In the best case, the algorithm stops when there are 0 objects left in the list.
EDIT
What I mean by circular fashion is this: 0,1,2,3,4,0,1,2,3,4 (also I need to be able to remove processes from the list, so the iterations should become smaller.) might look something like: Note that the algo stops when there are 0 in the list remaining
0,1,2,3,4
,0,2,3,4
2,3,4
2,4
4
while (it.hasNext()) {
Integer thisOne = it.next();
found=false;
// this process, can be removed from the list
// because cN = its current need
// a = how much the process is allocated already
// cR=bank's current resources
// so if cN - a <= cR, we know there is no deficit
// we can satisfy this process, and remove it from the list
// of needy processes
if(noDeficit(cN[thisOne], a[thisOne], cR)){
// we take away its resources and give them to the bank
Utility.add(cR, a[thisOne]);
Utility.zeroOut(cN[thisOne]);
Utility.zeroOut(a[thisOne]);
found = true;
// we remove it from the list of processes
it.remove();
}if(!found) return false;
}
Not really getting what your "found" condition should do, but here's an approach.
//todo create loop condition for stopping, eg originalList.size() > 0
//eg
List<Integer> itemsToRemoveList = new ArrayList<Integer>();
while (originalList.size() > 0) {
Iterator it = originalList.iterator();
while (it.hasNext()) {
Integer thisOne = it.next();
found=false;
// this process, can be removed from the list
if(noDeficit(cN[thisOne], a[thisOne], cR)){
// we take away its resources and give them to the bank
Utility.add(cR, a[thisOne]);
Utility.zeroOut(cN[thisOne]);
Utility.zeroOut(a[thisOne]);
// we remove it from the list of processes
itemsToRemoveList.add(thisOne);
}
} //end loop
for (Integer integerToRemove : itemsToRemoveList) {
originalList.remove(integerToRemove);
}
itemsToRemoveList.clear();
}

How to avoid ConcurrentModificationException while iterating this collection?

I need to iterate over a collection of items & sometimes add to that collection at the same time. However, incase I add while iterating then I just start the iteration from fresh by breaking out of iteration loop & restarting iteration from beginning. However this leads to
ConcurrentModificationException. [code below]
List<Integer> collection = new ArrayList<>();
for (Integer lobId: collection) {
..
if (someCondition) {
collection.add(something);
break;
}
}
How could I possibly do something like above avoiding ConcurrentModificationException?
Would it be correct to simply use an Array instead of ArrayList to avoid this exception ?
Is there any type of specialized collection for this ?
--
Edit:
I dont want to create a new copy for this arraylist because I'm repeating this entire iteration process multiple times unless some requirement is completed. Creating a new copy each time would bring in some extra overhead, which I would like to avoid if somehow possible.
Also if possible I would like to maintain a sorted order & unique values in that collection. Is there anything that is ready to use in any library? Otherwise I could sort it at the end of iteration process & remove duplicates. That will also do fine for me.
Use another collection for the additions and combine them at the end.
List<Integer> collection = new ArrayList<>();
collection.add(...)
...
List<Integer> tempCollection = new ArrayList<>();
for (Integer lobId: collection ) {
..
if (someCondition) {
tempCollection.add(something);
break;
}
}
collection.addAll(tempCollection);
This code cannot lead to ConcurrentModificationException because after you add an element you break the loop and dont use iterator anymore
if I understand you right, you want to iterate over the list , if some condition , you want to break the iteration , and an item and start fresh .
In the case do this:
List<Integer> collection = new ArrayList<>();
boolean flag = false;
Integer item =
for (Integer lobId: collection) {
..
if (someCondition) {
flag = true;
item = something;
break;
}
}
if (flag){
collection.add(item);
}
if someone else is going to change the list outside out loop - you will need to sync those access - read iterator thread safe , and use the other answers here like copying the list or some other copy on write
ConcurrentModificationException basically means that you're iterating over a Collection with one iterator (albeit implicitly defined by your enhanced for loop) and invalidating it on the fly by changing the Collection itself.
You can avoid this by doing the modifications via the sameiterator:
List<Integer> collection = new ArrayList<>();
ListIterator<Integer> iter = collection.listIterator();
while (iter.hasNext()) {
Integer currVal = iter.next();
if (someCondition) {
iter.add(something); // Note the addition is done on iter
break;
}
}
Don't use for each, use the good old
for(int i=0; i<collection.size();i++)

Hashset objects

I'm writing a piece of code which takes a great deal of objects and adds them to another array. The catch is, I don't want any duplicates. Is there a way I could implement a Hashset to solve this problem?
public static Statistic[] combineStatistics(Statistic[] rptData, Statistic[] dbsData) {
HashSet<Statistic> set = new HashSet<Statistic>();
for (int i=0; i<rptData.length; i++) {
set.add(rptData[i]);
}
/*If there's no data in the database, we don't have anything to add to the new array*/
if (dbsData!=null) {
for (int j=0; j<dbsData.length;j++) {
set.add(dbsData[j]);
}
}
Statistic[] total=set.toArray(new Statistic[0]);
for (int workDummy=0; workDummy<total.length; workDummy++) {
System.out.println(total[workDummy].serialName);
}
return total;
}//end combineStatistics()
Properly implement equals(Object obj) and hashCode() on YourObject if you expect value equality instead of reference equality.
Set<YourObject> set = new HashSet<YourObject>(yourCollection);
or
Set<YourObject> set = new HashSet<YourObject>();
set.add(...);
then
YourObject[] array = set.toArray(new YourObject[0])
I think you should pay attention to:
1 - what to do if there is a duplicate in the original Collection? Use the first added to the array? Use the other(s)?
2 - You definitely need to implement equals and hashcode so that you can tell what are duplicate objects
3 - Are you going to create a fixed size array and then won't add anymore objects? Or are you going to keep adding stuff?
You can use any kind of Set actually, but if you use LinkedHashSet, then you will have a defined iteration order (which looks like an array). HashSet wont't garantee any order and TreeSet will try to order data ascending.
Depends on what you are referring to as a duplicate. If you mean an identical object, then you could use a List and simply see if the List contains the object prior to adding it to the list.
Object obj = new Object();
List<Object> list = new ArrayList<Object>();
if (!list.contains(obj)) {
list.add(obj);
}

List that can only contain a value once

This is most certainly a noob question, but I haven't been able to find a good answer on Google or here, so I have to ask:
What kinda list should I use in Java, when I just want a value to be added once?
The problem is that I'm doing a web technology project in college (a webshop), and I have this cloud I connect too. I can the request the customer ID´s from those who bought items in my shop. What I want to do is extract these ID´s and add them to a list. But when extracting them I get the ID returned for every item they have bought, so I want a list that can check: "This value is already in this list, do nothing", or "This ID is not in the list, lets add the ID"
Is there a list that can do this, or a way to do it with a list without it getting too complicated?
You want a Set, this is the data structure that prevents duplicates. This is a Collection so you can define a function like so:
public Collection<MyObject> foo()
{
return new HashSet<MyObject>();
}
and at a later time change the return internally to this:
public Collection<MyObject> foo()
{
return new ArrayList<MyObject>();
}
And your API won't break.
A Set contains every value only once.
Though, the problem with HashSet is that the order in which the elements were added gets lost. So if you want to preserve the order of elements, I would suggest using a LinkedHashSet.
With a LinkedHashSet, iterating over the elements will return them in the order they were inserted.
public static void main(String[] args) {
Set<String> hashSet = new HashSet<>();
hashSet.add("first");
hashSet.add("second");
hashSet.add("third");
for (String s : hashSet) {
System.out.println(s); // no particular order
}
Set<String> linkedHashSet = new LinkedHashSet<>();
linkedHashSet.add("first");
linkedHashSet.add("second");
linkedHashSet.add("third");
for (String s : linkedHashSet) {
System.out.println(s); // "first", "second", "third"
}
}
public boolean insertRecord(Programmer targetProgrammer, List programmerList) {
boolean flag = false;
for (Programmer p : programmerList){
if (targetProgrammer.getId() == p.getId()) {
return true;
}
}
return flag;
}
// Then when you invoke:
Programmer target = new Programmer(1,"Dev","Java");
if (!insertRecord(target, myList)) {
myList.add(target);
}
What you will be looking for is a Set, as a Set is a Collection that contains no duplicates.
There are a few types that you could use depending on your needs:
HashSet
LinkedHashSet
CopyOnWriteArraySet
EnumSet
TreeSet
ConcurrentSkipListSet
Better use HashSet as it takes care of your problem of unique IDs implicitly. Still better is SortedSet where you can have the unique elements printed in sorted order automatically.

Categories