如何迭代 SortedSet 以修改其中的项目

发布于 2024-12-18 16:45:50 字数 178 浏览 4 评论 0 原文

假设我有一个列表。在 for 循环中修改列表的项目没有问题:

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

但我有一个 SortedSet 而不是列表。我怎样才能用它做同样的事情? 谢谢

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

爱冒险 2024-12-25 16:45:50

首先,Set 假设它的元素是不可变的(实际上,可变元素允许的,但它们必须遵守一个非常具体的约定,我怀疑你的类会这样做) 。

这意味着通常您无法像处理列表那样就地修改集合元素。

Set 支持的两个基本操作是添加和删除元素。修改可以被认为是删除旧元素,然后添加新元素:

  1. 您可以在迭代时使用 Iterator.remove();
  2. 您可以将添加的内容累积在单独的容器中并调用 Set.addAll() 位于末尾。

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.
巴黎夜雨 2024-12-25 16:45:50

您无法修改集合的键,因为它会导致集合重新排序/重新排序。因此,迭代将如何进一步运行将是未定义的行为。

您可以使用 iterator.remove() 删除元素。但你不能添加元素,通常更好的解决方案是将它们累积在一个新集合中,并在迭代后 addAll 。

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);

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);
鹤舞 2024-12-25 16:45:50

从 Java 1.6 开始,您可以使用 NavigableSet

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

秋风の叶未落 2024-12-25 16:45:50

您应该使用 迭代器< /a> 或更好的是增强的 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();
}

EDIT

Kan 在修改项目键方面提出了很好的观点。假设您的类的 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.
}

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.
}
白龙吟 2024-12-25 16:45:50

你不能那样做。但你可以尝试一下,也许你会成功,也许你会得到ConcurrentModificationException。记住这一点非常重要,在迭代时修改元素可能会产生意想不到的结果。您应该将这些元素收集到某个集合中。并在迭代后一一修改。

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.

不念旧人 2024-12-25 16:45:50

仅当 id 未用于 equals 或用于排序集的比较器时,这才有效:

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

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++;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文