【问题标题】:Cull all duplicates in a set剔除集合中的所有重复项
【发布时间】:2015-08-28 21:25:59
【问题描述】:

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

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

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

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

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 不同。如果可能的话,我想在没有循环的情况下这样做。

【问题讨论】:

  • 我很难理解你在问什么。如果您从列表中创建一个集合,它将在列表中生成一组不同的项目。你还要求什么?
  • 如果我理解正确,您只想将那些唯一的项目放入集合中,或者等效地,从集合中排除列表中重复的对象。我说的对吗?
  • 巴兰卡 - 是的!这就是我打算做的事情。

标签: java set set-theory


【解决方案1】:

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

如果你的PVector 类有一个好的hashCode() 方法,HashSets 是相当高效的,所以这个性能不会太差。

未经测试:

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 的所有元素。

【讨论】:

  • 谢谢 Hoopje,我会研究 Bag 和 MultiSet。如果可能的话,我正在尝试在本机 Java(没有循环)中执行此操作。
  • 我知道这是最有效的方法。再次感谢!
【解决方案2】:

你要找的是intersection:

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

如果您想要List 中的intersection 和现有的Set,则从List 创建一个Set,然后使用Sets.intersection() from Guava 来获取这两个集合的共同点。

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

返回两个集合交集的不可修改视图。返回的集合包含所有 两个支持集包含的元素。迭代顺序 返回的 set 与 set1 的匹配。结果未定义,如果 set1 和 set2 是基于不同等价关系的集合(如 HashSet、TreeSet、IdentityHashMap的keySet都是)。

注意:当 set1 为 两组中较小的一组。如果你有理由相信你的一个 套数一般会比另一套小,先通过。 不幸的是,由于这个方法设置了返回的泛型类型 根据传递的第一组的类型设置,这可能很少见 案例迫使您进行演员表,例如:

设置 aFewBadObjects = ... 设置 manyBadStrings = ...

// 非字符串不可能在交叉点中
SuppressWarnings("unchecked") Set badStrings = (Set) 集.intersection( aFewBadObjects, manyBadStrings);这很不幸,但应该很少出现。

你也可以很容易地做到unioncomplementdifferencecartesianProduct以及filtering。

【讨论】:

  • 谢谢 Jarrod,我相信这是朝着正确的方向发展。如果我可以从原始列表中获取 Set 以及所有已删除项目的另一个列表,我可以在 Set 和已删除项目之间进行区分。我将研究一种快速跟踪已删除项目的方法(不循环)。
【解决方案3】:

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

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

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

【讨论】:

  • 谢谢卡尔,但我倾向于找到更有效的方法。
【解决方案4】:

好的,这是我想出的解决方案,我敢肯定还有更好的解决方案,但这个对我有用。感谢所有给予指导的人!

要获得唯一的项目,您可以运行 Set,其中 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);

【讨论】:

    猜你喜欢
    • 2018-08-08
    • 2020-06-23
    • 2017-05-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-25
    • 2019-02-17
    • 2015-11-24
    相关资源
    最近更新 更多