How to iterate over a SortedSet to modify items within

北战南征 提交于 2020-01-03 19:57:52

问题


lets say I have an List. There is no problem to modify list's item in for loop:

for (int i = 0; i < list.size(); i++) { list.get(i).setId(i); }

But I have a SortedSet instead of list. How can I do the same with it? Thank you


回答1:


First of all, Set assumes that its elements are immutable (actually, mutable elements are permitted, but they must adhere to a very specific contract, which I doubt your class does).

This means that generally you can't modify a set element in-place like you're doing with the list.

The two basic operations that a Set supports are the addition and removal of elements. A modification can be thought of as a removal of the old element followed by the addition of the new one:

  1. You can take care of the removals while you're iterating, by using Iterator.remove();
  2. You could accumulate the additions in a separate container and call Set.addAll() at the end.



回答2:


You cannot modify set's key, because it causes the set rehasing/reordering. So, it will be undefined behaviour how the iteration will run further.

You could remove elements using iterator.remove(). But you cannot add elements, usually better solution is to accumulate them in a new collection and addAll it after the iteration.

Set mySet = ...;
ArrayList newElems = new ArrayList();

for(final Iterator it = mySet.iterator(); it.hasNext(); )
{
  Object elem = it.next();
  if(...)
   newElems.add(...);
  else if(...)
   it.remove();
  ...
}
mySet.addAll(newElems);



回答3:


Since Java 1.6, you're able to use a NavigableSet.




回答4:


You should use an Iterator or better still the enhanced for-loop syntax (which depends on the class implementing the Iterable interface), irrespective of the Collection you're using. This abstracts away the mechanism used to traverse the collection and allows a new implementation to be substituted in without affecting the iteration routine.

For example:

Set<Foo> set = ...

// Enhanced for-loop syntax
for (Foo foo : set) {
 // ...
} 

// Iterator approach
Iterator it = set.iterator();
while (it.hasNext()) {
  Foo foo = it.next();
}

EDIT

Kan makes a good point regarding modifying the item's key. Assuming that your class's equals() and hashCode() methods are based solely on the "id" attribute (which you're changing) the safest approach would be to explicitly remove these from the Set as you iterate and add them to an "output" Set; e.g.

SortedSet<Foo> input = ...
SortedSet<Foo> output = new TreeSet<Foo>();

Iterator<Foo> it = input.iterator();
while (it.hasNext()) {
  Foo foo = it.next();
  it.remove(); // Remove from input set before updating ID.
  foo.setId(1);
  output.add(foo); // Add to output set.
}



回答5:


You cannot do that. But you may try, maybe you'll succeed, maybe you'll get ConcurrentModificationException. It's very important to remember, that modifying elements while iterating may have unexpected results. You should instead collect that elements in some collection. And after the iteration modify them one by one.




回答6:


This will only work, if id is not used for equals, or the comperator you used for the sorted set:

int counter = 0;
for(ElementFoo e : set) {
  e.setId(counter);
  couter++;
}


来源:https://stackoverflow.com/questions/8311011/how-to-iterate-over-a-sortedset-to-modify-items-within

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!