删除Java中重复项的最快速有效的方法

时间:2017-05-18 12:25:06

标签: java hashmap hashset

我想删除数据中的重复值。我知道它经常在stackoverflow中被观察到的问题,但我的问题有点不同,因为现在我正在处理非常大的数据。因此,我必须在代码中考虑最多的执行时间。

如下面的代码段所示,我制作了一个简单的代码来删除重复的值。

// Suppose that the dataset is very huge so that
// multi-node resources should be necessary.    
String[] data = new String[10_000_000];

HashMap<String, String> uniqueItems = new HashMap<>();

for (int i = 0; i < data.length; i++) {
    if (uniqueItems.containsKey(data[i])) {
        uniqueItems.remove(data[i]);
        uniqueItems.put(data[i], "inserted");
    } else {
        uniqueItems.put(data[i], "inserted");
    }
}

但是,我不喜欢它,因为我认为其他更好的数据结构或不同的算法可以有效地删除重复数据而不是我的代码。

所以我想寻找更好的方法,在数据很大时快速删除重复的值 如果您能告诉我删除重复值的最快方法,我将不胜感激。

而且,我想知道重复值的数量是否会影响性能。我的意思是如果重复值是原始数据的50%,那么最佳算法和数据结构的选择将会改变吗?如果是这样,我想找到一种在一般情况下可以取得良好表现的方法。

2 个答案:

答案 0 :(得分:5)

将您的uniqueItems转换为HashSet<String>,将转换简单地转换为:

uniqueItems.add(data[i]);

如果add返回true,那么您已插入一个唯一字符串; false如果重复。

在最好的情况下,两种算法都应该在 O(n)时间运行,但是如果你不关心值(对于给定的密钥),则使用HashMap是愚蠢的和浪费资源。 HashSet更适合这种情况。

您还可以尝试使用TreeSet<String>查看哪种方法最适合您的特定数据集。鉴于JDK 8新的HashSet实现,可能会更糟糕:过度拥挤的存储桶会自动存储为迷你树集,即使散列函数表现不佳,也能提供有竞争力的性能。 (此优化仅适用于Comparable类型String类型。

强力搜索数组。在一个简单的基于数组的算法中,在插入每个元素之前搜索整个数组,您将获得非常糟糕的 O(n²)性能。

因此,您可能会首先排序您的数据,将重复的元素放在附近。这样可以获得更快的 O(n log n)性能,但在一般情况下仍然落后于HashMap/HashSet版本。

线性理论上最好。如果不访问每个元素至少一次,则无法检测所有重复项。因此,我们当前的 O(n)时间复杂度实际上是您在这里所能做到的最佳。

当然,你总是可以尝试削减Big O notation中的一些隐藏的常量,但是你不会以渐近更好的算法到达。

答案 1 :(得分:1)

在您的示例中,data [i]值用作&#39;键 HashMap uniqueItems。

HaspMap将始终具有唯一键。现有密钥 将被put()操作覆盖。如果你不需要conatinsKey() 你想添加一个新元素。

为什么要删除并插入现有密钥?