【问题标题】:How to detect duplicate Lists in Map<String,List<String>>如何检测 Map<String,List<String>> 中的重复列表
【发布时间】:2013-09-18 16:15:00
【问题描述】:

我有一张Map&lt;String,List&lt;String&gt;&gt; 形式的地图。关键是文档编号,List 是符合某些条件并在文档中找到的术语列表。 为了检测重复文档,我想知道List&lt;String&gt; 中的任何两个是否具有完全相同的元素(这包括重复值)。 List&lt;String&gt; 已排序,因此我可以遍历地图并首先检查 List.size()。对于任意两个列表 大小相同,然后我必须将这两个列表与List.equals() 进行比较。 地图和相关列表永远不会很大,所以即使这种蛮力方法不能很好地扩展它 就足够了。但我想知道是否有更好的方法。一种不涉及太多的方式 显式循环和一种在 Map 和/或 List 变得更大时不会产生组合爆炸的方法。 最后,我需要的只是对这个问题的是/否回答:是否有任何列表相同?

【问题讨论】:

  • 您无法比O(n) 更好地比较两个列表是否相等。你想用相等的列表做什么?
  • Rohit,我不想对列表做任何事情。我只需要一个是/否的答案:是否至少有一个重复项?

标签: java collections


【解决方案1】:

您可以将列表逐个添加到集合数据结构中。令人高兴的是,add 方法会告诉您集合中是否已经存在相等列表:

HashSet<List<String>> set = new HashSet<List<String>>();
for (List<String> list : yourMap.values()) {
    if (!set.add(list)) {
        System.out.println("Found a duplicate!");
        break;
    }
}

此算法将在 O(N) 时间内查找是否存在重复列表,其中 N 是字符串列表中的字符总数。这比比较每对列表要好得多,因为对于 n 个列表,有 n(n-1)/2 对要比较。

【讨论】:

  • 乔尼,好主意!我会用这个。
【解决方案2】:

使用Map.containsValue()。不会比你描述的更有效,但代码会更干净。链接->http://docs.oracle.com/javase/7/docs/api/java/util/Map.html#containsValue%28java.lang.Object%29

另外,根据你这样做的确切原因,可能值得研究这个界面 -> http://google-collections.googlecode.com/svn/trunk/javadoc/com/google/common/collect/BiMap.html

【讨论】:

    【解决方案3】:

    不确定这是否是一种更好的方法,但一种更简洁的方法是创建一个实现 Comparable 并包含您的 List 之一的对象。您可以像上面描述的那样实现 hashcode() 和 equals() 并更改您的地图以包含此类的实例而不是直接包含列表。

    然后您可以使用 HashSet 有效地发现哪些列表是相等的。或者你可以将map的values集合添加到HashSet中,然后将hashset的大小与Map的大小进行比较。

    【讨论】:

      【解决方案4】:

      来自'List.equals(Object o)'的JavaDoc:

      比较指定对象与此列表是否相等。退货 当且仅当指定的对象也是一个列表时才为真,这两个列表 具有相同的大小,并且两者中所有对应的元素对 列表是相等的。 (两个元素 e1 和 e2 相等 if (e1==null ? e2==null : e1.equals(e2))。)换句话说,两个列表被定义为 如果它们以相同的顺序包含相同的元素,则它们是相等的。这 定义确保 equals 方法可以正常工作 List 接口的不同实现。

      这让我相信它正在做你提议的同样的事情:检查以确保两边都是一个列表,然后比较大小,然后检查每一对。我不会在那里重新发明轮子。

      您可以改用 hashCode(),但那里的 JavaDoc 似乎也表明它正在循环:

      返回此列表的哈希码值。列表的哈希码是 定义为以下计算的结果:

       int hashCode = 1;
        Iterator<E> i = list.iterator();
        while (i.hasNext()) {
            E obj = i.next();
            hashCode = 31*hashCode + (obj==null ? 0 : obj.hashCode());
        }
      

      所以,我认为您没有节省任何时间。但是,您可以编写一个自定义 List 来计算放入项目时的哈希值。然后您可以抵消执行循环的成本。

      【讨论】:

      • 使用哈希码不会帮助您比较两个列表是否相等。但是,如果我正确理解问题,列表相等比较的 number 看起来像 n(n-1)/2,而哈希码(或 HashSet)肯定会有助于加快速度。
      • hashCode 不能保证相等,但是当它被编码时,它会显示两个列表是否最有可能相等,因为它的基本实现将所有条目作为定义哈希的输入。因此,您可以相互测试两者的哈希码,然后确定是否需要进行进一步比较。但是,由于它们似乎都循环一次,我认为您根本不需要保存任何指令。
      猜你喜欢
      • 2016-05-21
      • 1970-01-01
      • 1970-01-01
      • 2020-03-17
      • 2021-09-04
      • 2021-04-25
      • 1970-01-01
      • 1970-01-01
      • 2020-08-01
      相关资源
      最近更新 更多