Как перебрать SortedSet для изменения элементов внутри
Допустим, у меня есть список. Нет проблем изменить элемент списка в цикле for:
for (int i = 0; i < list.size(); i++) { list.get(i).setId(i); }
Но у меня есть SortedSet вместо списка. Как я могу сделать то же самое с этим? Спасибо
6 ответов
Прежде всего, Set
предполагает, что его элементы являются неизменяемыми (на самом деле, изменяемые элементы разрешены, но они должны придерживаться очень конкретного контракта, что, я сомневаюсь, ваш класс делает).
Это означает, что, как правило, вы не можете изменить заданный элемент на месте, как вы делаете со списком.
Две основные операции, которые Set
Опоры - это добавление и удаление элементов. Модификация может рассматриваться как удаление старого элемента с последующим добавлением нового:
- Вы можете позаботиться об удалении во время итерации, используя
Iterator.remove()
; - Вы можете накопить дополнения в отдельном контейнере и вызвать
Set.addAll()
в конце.
Вы не можете изменить ключ набора, потому что это вызывает изменение набора / переупорядочение набора. Таким образом, поведение итерации будет продолжаться неопределенным образом.
Вы можете удалить элементы, используя iterator.remove(). Но вы не можете добавлять элементы, обычно лучшее решение - это накапливать их в новой коллекции и добавлять все после итерации.
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);
Вы должны использовать Iterator
или, что еще лучше, расширенный синтаксис цикла for (который зависит от класса, реализующего Iterable
интерфейс), независимо от Collection
вы используете Это абстрагирует механизм, используемый для обхода коллекции, и позволяет заменить новую реализацию, не затрагивая процедуру итерации.
Например:
Set<Foo> set = ...
// Enhanced for-loop syntax
for (Foo foo : set) {
// ...
}
// Iterator approach
Iterator it = set.iterator();
while (it.hasNext()) {
Foo foo = it.next();
}
РЕДАКТИРОВАТЬ
Кан делает хорошие замечания относительно изменения ключа элемента. Предполагая, что ваш класс equals()
а также hashCode()
методы основаны исключительно на атрибуте "id" (который вы меняете), самый безопасный способ - явно удалить их из Set
как вы итерируете и добавляете их в "вывод" Set
; например
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.
}
Тебе этого не сделать. Но вы можете попробовать, может быть, вам удастся, может быть, вы получите ConcurrentModificationException
, Очень важно помнить, что изменение элементов во время итерации может привести к неожиданным результатам. Вместо этого вы должны собрать эти элементы в некоторой коллекции. И после итерации измените их один за другим.
Это будет работать только если id
не используется для равных, или компаратор, который вы использовали для отсортированного набора:
int counter = 0;
for(ElementFoo e : set) {
e.setId(counter);
couter++;
}