【问题标题】:Deduplication using a Java Set使用 Java 集的重复数据删除
【发布时间】:2019-02-16 09:49:49
【问题描述】:

我有一个对象的集合,我们称它们为 A、B、C、D……,有些是等价的。如果 A 和 C 相等,那么我想用对 A 的引用替换对 C 的每个引用。这意味着(a)对象 C 可以被垃圾收集,释放内存,并且(b)我以后可以使用“==”比较对象来代替昂贵的equals() 操作。 (这些对象很大,equals() 操作很慢。)

我的直觉是使用java.util.Set。当我遇到 C 时,我可以很容易地看到 Set 中是否有一个等于 C 的条目。但如果有,似乎没有简单的方法来找出那个条目是什么,并替换我对现有条目的引用。我弄错了吗?遍历所有条目以找到匹配的条目显然是行不通的。

目前,我使用的不是Set,而是Map,其中值始终与键相同。调用map.get(C) 然后找到A。这可行,但感觉非常复杂。有没有更优雅的方法?

【问题讨论】:

  • 这篇文章 (stackoverflow.com/questions/7283338/…) 尤其是它的第一个答案与这篇文章非常相关,尽管我不认为它是重复的。但据我所知, Map 在这里并不少见。
  • 查看HashSetpublic boolean add(E e) { return map.put(e, PRESENT)==null; }的来源。如果我没记错的话,这正是你想要的行为?
  • @NeilEdelman 不返回对象,如果没有映射则返回 true 或 false。如果对象已经存在则返回 false。
  • 如果我错了,请纠正我,您想使用Set 来避免重复对象,但您仍然覆盖.equals() 方法HashMapSet 使用.equals() 进行比较对象,那你为什么不使用ArrayList(),但在插入之前你可以用contains()检查,你可以通过indexof()获取索引
  • 您还拥有 SortedSet,它使您能够进行二进制查找。但我不认为 MAP 是个坏主意。如果您不需要订单,我会使用地图。

标签: java collections


【解决方案1】:

这个问题不是简单的去重:它是规范化的一种形式。

标准方法是使用Map 而不是Set。下面是如何做到这一点的草图:

public <T> List<T> canonicalizeList(List<T> input) {
    HashMap<T, T> map = new HashMap<>();
    List<T> output = new ArrayList<>();
    for (T element: input) {
        T canonical = map.get(element);
        if (canonical == null) {
            element = canonical;
            map.put(canonical, canonical);
        }
        output.add(canonical);
    }
    return output;
}

请注意,这是O(N)。如果您可以安全地假设input 中重复的百分比可能很小,那么您可以将mapoutput 的容量设置为input 的大小。


现在你似乎在说你已经这样做了(最后一段),你在问是否有更好的方法。据我所知,没有。 (HashSet API 可以让您测试一个集合是否包含等于 element 的值,但它不会让您找出它在 O(1) 中的值。)

不管怎样,HashSet&lt;T&gt; 类实际上是作为HashMap&lt;T, T&gt; 实现的。因此,直接使用HashSet 不会节省时间或空间...

【讨论】:

  • 您可以将其缩短为 input.stream().distinct().collect(Collectors.toList())
  • 是的......但是OP可能不理解它:-)
  • 谢谢。这似乎证实了没有比我已经在做的更好的方法了。也许我应该将我的 Map 结构封装在一个隐藏实现类中的笨拙而不是到处暴露它的东西中。
猜你喜欢
  • 2012-03-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-03-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多