有没有更快的方法来使用Java查找不同的元素

时间:2014-08-16 10:12:36

标签: java

我编写了代码来查找大量字符串中的distinct元素。代码如下所示

HashMap<String, Integer> countMap = new HashMap<>();
String[] str={"aa","bb","cc","bb","aa","cc","aa","bb","cc","bb"};
for (String e : str) {
  if (!countMap.containsKey(e)) {
    countMap.put(e, 1);
  } 
}
Iterator it=countMap.keySet().iterator();
String[] db= new String[countMap.size()];
for(int i=0;i<countMap.size();i++){
  db[i]=(String)it.next();
  System.out.println(db[i]);
}

是否有比这更快的代码,因为我必须处理非常大的数组。

3 个答案:

答案 0 :(得分:5)

这不会(相当)更快,但使用HashSet肯定会更优雅:

String[] str={"aa","bb","cc","bb","aa","cc","aa","bb","cc","bb"};
Set<String> distinct = new HashSet<>(Arrays.asList(str));
for(String s : distinct) {
    System.out.println(s);
}

答案 1 :(得分:2)

您可以使用Java 8并行化所有工作:

String[] largeArray = null;

Set<String> distinctStrings = 
         Arrays.stream(largeArray).parallel()
        .collect(Collectors.toConcurrentMap((s) -> s, (s) -> s)).keySet();

这会缩放,直到ConcurrentMap中的争用成为问题。

您还可以在流上使用distinct功能:

Set<String> distinctStrings = Arrays.stream(largeArray).parallel()
    .distinct().collect(Collectors.toSet())

<强>微基准

两个方法以1m GUID作为输入运行(最坏情况),进行100次重复,测量得到它的时间。

Statistics stats = new Statistics();
for (int i = 0; i < 100; i++) {
  String[] largeArray = generate(1_000_000); // generates 1m UUIDs
  Stopwatch watch = Stopwatch.createStarted();

  // add the lambda here

  long time = watch.elapsed(TimeUnit.MILLISECONDS);
  System.out.println(distinctStrings.size());
  stats.add(time);
}

注意这并不能衡量可扩展性,您需要改变该实验的输入大小,以便更准确地了解更大输入的速度。

对于Java Stream Distinct解决方案:

[Min=358.0, Max=2236.0, Median=456.0, Mean=542.26, StandardDeviation=335.21174263441304]

对于ConcurrentMap解决方案:

[Min=85.0, Max=1020.0, Median=120.0, Mean=153.58, StandardDeviation=119.78281846742465]

使用HashSet

连续排序
[Min=258.0, Max=1312.0, Median=281.0, Mean=307.39, StandardDeviation=125.63032237481526]

<强>结果

通过并行化可以获得相当快的速度,ConcurrentMap解决方案在输入大小上比顺序版本执行得更好(对于更大的输入大小/更多线程,可能会有所不同)。

并行Stream#distinct比顺序版慢。

答案 2 :(得分:0)

哈希是正确的方法。我们可以选择Map,而不是保留Set。仅使用地图进行内部设置。

String[] str={"aa","bb","cc","bb","aa","cc","aa","bb","cc","bb"};
HashSet<String> uniques = new HashSet<String>();
for (String string : str) {
    uniques.add(string);
}

String[] result = new String[uniques.size()];
uniques.toArray(result);
System.out.println(Arrays.toString(result));