如何从Java中的LinkedHashSet中获取一个元素?

use*_*929 7 java iterator linkedhashset

我正在寻找将给定集合划分为不相交子集的代码.例如,一组足球运动员,我们根据他们所属的球队对他们进行分区.我最终想要一份代表名单,即每队的一名球员.

所有足球运动员都了解球队中的所有其他球员 - 这与复杂性非常相关.所以,我目前关于如何做到这一点的想法如下(set目前在哪里LinkedHashSet<T>):

while (!set.isEmpty()) {
    E e = set.iterator().next();
    makeRepresentative(e);
    set.remove(AllPlayersOnSameTeamAs(e));
}
Run Code Online (Sandbox Code Playgroud)

但是,在while循环的每个步骤中构建一个新的迭代器感觉很奇怪.LinkedHashSet应该在firstElement()内部具有某种功能(对于其LinkedList行为),但由于某种原因我无法找到如何执行此操作.我也试过了一个foreach循环,但结果是一个java.util.ConcurrentModificationException.

我该如何正确地做到这一点?

Joe*_*e K 1

while (!set.isEmpty()) {    
    Collection<E> toBeRemoved = new ArrayList<E>();
    E first = set.iterator().next();
    doSomethingWith(e);
    for (E e : set) {
        if (similar(first, e)) toBeRemoved.add(e);
    }
    set.removeAll(toBeRemoved);
}
Run Code Online (Sandbox Code Playgroud)

阅读您的编辑并更好地理解后,以下是您可能喜欢的解决方案:

Collection<E> processed = new ArrayList<E>();
for (E e1 : set) {
    boolean similar = false;
    for (E e2 : processed) {
        if (similar(e1, e2)) similar = true;
    }
    if (!similar) {
        doSomethingWith(e1);
        processed.add(e1);
    }
}
set.clear();
Run Code Online (Sandbox Code Playgroud)

请注意,在不了解“相似”定义的更多信息的情况下,这个问题本质上是二次的。使其成为线性或次二次的唯一方法是是否有一种方法可以将相似的元素散列到相同的键。在这种情况下,您可以使用上面的第二种策略,但修改processed结构和检查先前相似元素的部分以提高效率(当前该步骤与相似组的数量呈线性,这可能与元素总数呈线性) 。

此外,任何二次方的东西肯定会使用比常量内存更多的东西。如果你想要恒定的内存,这就是你能做的最好的事情(这绝对是二次时间):

while (!set.isEmpty()) {
    Iterator<E> iter = set.iterator();
    E first = iter.next();
    doSomethingWith(first);
    while (iter.hasNext()) {
        if (similar(first, iter.next())) iter.remove();
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意,使用 iter.remove() 修复了之前遇到的并发修改问题。