剔除集合中的所有重复项

Cull all duplicates in a set

我正在使用 Set 来隔离列表的唯一值(在这种情况下,我得到了一组点):

Set<PVector> pointSet = new LinkedHashSet<PVector>(listToCull);

这将 return 一组唯一点,但是对于 listToCull 中的每个项目,我想测试以下内容:如果有重复项,剔除所有重复项。换句话说,我希望 pointSet 代表 listToCull 中已经唯一的项目集(pointSet 中的每个项目在 listToCull)。关于如何实施的任何想法?

编辑 - 我认为我的第一个问题需要更多的澄清。下面是一些将执行我所要求的代码,但我想知道是否有更快的方法。假设 listToCull 是具有重复项的 PVectors 列表:

Set<PVector> pointSet = new LinkedHashSet<PVector>(listToCull);
    List<PVector> uniqueItemsInListToCull = new ArrayList<PVector>();
    for(PVector pt : pointSet){
        int counter=0;
        for(PVector ptCheck : listToCull){
            if(pt==ptCheck){
                counter++;
            }
        }
        if(counter<2){
            uniqueItemsInListToCull.add(pt);
        }
    }

uniqueItemsInListToCull 将不同于 pointSet。如果可能的话,我想在没有循环的情况下执行此操作。

你要找的是 intersection:

假设 PVector 顺便提一句,这个名字很糟糕 )实现了 hashCode()equals() 正确,Set 将消除重复。

如果您想要 Listintersection 和现有的 SetList 创建一个 Set 然后使用 Sets.intersection() from Guava得到两组共有的。

public static <E> Sets.SetView<E> intersection(Set<E> set1, Set<?> set2) 

Returns an unmodifiable view of the intersection of two sets. The returned set contains all elements that are contained by both backing sets. The iteration order of the returned set matches that of set1. Results are undefined if set1 and set2 are sets based on different equivalence relations (as HashSet, TreeSet, and the keySet of an IdentityHashMap all are).

Note: The returned view performs slightly better when set1 is the smaller of the two sets. If you have reason to believe one of your sets will generally be smaller than the other, pass it first. Unfortunately, since this method sets the generic type of the returned set based on the type of the first set passed, this could in rare cases force you to make a cast, for example:

Set aFewBadObjects = ... Set manyBadStrings = ...

// impossible for a non-String to be in the intersection
SuppressWarnings("unchecked") Set badStrings = (Set) Sets.intersection( aFewBadObjects, manyBadStrings); This is unfortunate, but should come up only very rarely.

您还可以非常轻松地执行 unioncomplementdifferencecartesianProduct 以及 filtering。

您将不得不自己进行一些编程:创建两个空集; on 将包含唯一元素,另一个包含重复项。然后循环遍历listToCull的元素。对于每个元素,检查它是否在重复集中。如果是,请忽略它。否则,检查它是否在唯一元素集中。如果是,请将其删除并添加到重复项集中。否则,将其添加到唯一元素集中。

如果你的PVectorclass有一个很好的hashCode()方法,HashSet的效率还是挺高的,所以性能不会太差。

未测试:

Set<PVector> uniques = new HashSet<>();
Set<PVector> duplicates = new HashSet<>();
for (PVector p : listToCull) {
    if (!duplicates.contains(p)) {
        if (uniques.contains(p)) {
            uniques.remove(p);
            duplicates.add(p);
        }
        else {
            uniques.add(p);
        }
    }
}

或者,您可以使用提供 BagMultiSet 的第三方库。这允许您计算每个元素在集合中出现的次数,然后在最后丢弃所有计数不同于 1 的元素。

所以您希望 pointSet 保存 listToCull 中没有重复项的项目?是吗?

我倾向于创建一个 Map,然后在列表上迭代两次,第一次为每个 PVector 赋一个零值,第二次为每个 PVector 的值加一个,所以在最后你有一张带有计数的地图。现在您对值正好等于 1 的地图键感兴趣。

它不是非常高效 - 您对列表项的操作次数超过了绝对必要的次数 - 但它非常干净和简单。

好的,这是我提出的解决方案,我相信还有更好的解决方案,但这个对我有用。感谢所有指路的人!

要获得独特的项目,您可以 运行 一个集合,其中 listToCull 是 PVectors 个具有重复项的列表:

    List<PVector> culledList = new ArrayList<PVector>();
    Set<PVector> pointSet = new LinkedHashSet<PVector>(listToCull);
    culledList.addAll(pointSet);

更进一步,假设您想要一个列表,您已经删除了 listToCull 中具有重复项的所有项目。您可以遍历列表并测试它是否在每个项目的集合中。这让我们做一个循环,而不是嵌套循环:

    Set<PVector> pointSet = new HashSet<PVector>(listToCull);
    Set<PVector> removalList = new HashSet<PVector>();//list to remove

    for (PVector pt : listToCull) {
        if (pointSet.contains(pt)) {
            removalList.add(pt);
        }
        else{
            pointSet.add(pt);
        }
    }
    pointSet.removeAll(removalList);
    List<PVector> onlyUniquePts = new ArrayList<PVector>();
    onlyUniquePts.addAll(pointSet);