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

时间:2012-09-12 00:10:25

标签: java iterator linkedhashset

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

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

while (!set.isEmpty()) {
    E e = set.iterator().next();
    makeRepresentative(e);
    set.remove(AllPlayersOnSameTeamAs(e));
}

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

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

2 个答案:

答案 0 :(得分: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);
}

在更好地阅读您的编辑和理解之后,这里有一个您可能喜欢的解决方案:

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

请注意,在不了解“类似”的定义的情况下,这个问题本质上是二次的。它可以被制成线性或次二次的唯一方法是,如果有一种方法将相似的元素散列到同一个键。在这种情况下,您可以使用上面的第二个策略,但修改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();
    }
}

请注意,使用iter.remove()可以修复以前的并发修改问题。

答案 1 :(得分:0)

我会一次性完成,跟踪我见过的球队。

Set<Team> processedTeams = new HashSet<>();
Set<Players> representatives = new HashSet<>();
for(e:players) {
  Team t = e.getTeam();
  if(processedTeams.contains(t))
    continue;
  processedTeams.add(t);
  representatives.add(e)
}