我有一个包含字符串的ArrayList,我想找到并返回列表中存在多次的所有值。大多数情况下都是寻找相反的结果(例如删除重复项,如distinct()),因此很难找到示例代码。
我能够想出以下代码:
这个代码似乎按预期工作,但并没有像我希望的那样显著提高速度,大约为120毫秒。这可能是因为它还需要针对每个项目遍历整个列表,但我不确定如何避免这种情况并仍然完成任务。
我知道这可能看起来像过早优化,但我的列表很容易达到100万+,而这个方法是我应用程序的关键部分,影响其他所有内容的时间安排。
你有没有看到我可以进一步优化这段代码的方法?也许使用某种高级Predicate?或者完全不同的方法?
编辑: 感谢您所有的建议,我能够想出一个明显更快的解决方案:
在相同的条件下运行,这可以在<5毫秒内通过我的列表。 如果我需要知道计数,所有的HashMap建议都将是很好的选择。不确定为什么Collections.frequency()方法不使用该技术。
我能够想出以下代码:
public synchronized List<String> listMatching(List<String> allStrings) {
long startTime = System.currentTimeMillis();
List<String> duplicates = allStrings.stream().filter(string -> Collections.frequency(allStrings, string) > 1)
.collect(Collectors.toList());
long stopTime = System.currentTimeMillis();
long elapsedTime = stopTime - startTime;
LOG.info("Time for Collections.frequency(): "+ elapsedTime);
return duplicates;
}
但是这个使用了Collections.frequency
,它会为每个元素循环整个列表并计算每个出现的次数。在我的目前大约4,000个字符串列表上运行需要约150ms。
对我来说有点慢,而且随着列表大小的增加,速度只会变得更慢。我重写了频率方法,使其在第二次出现时立即返回:
protected boolean moreThanOne(Collection<?> c, Object o) {
boolean found = false;
if (o != null) {
for (Object e : c) {
if (o.equals(e)) {
if (found) {
return found;
} else {
found = true;
}
}
}
}
return found;
}
并且我改变了我的方法来使用它:
public synchronized List<String> listMatching(List<String> allStrings) {
long startTime = System.currentTimeMillis();
List<String> duplicates = allStrings.stream().filter(string -> moreThanOne(allStrings, string))
.collect(Collectors.toList());
long stopTime = System.currentTimeMillis();
long elapsedTime = stopTime - startTime;
LOG.info("Time for moreThanOne(): "+ elapsedTime);
return duplicates;
}
这个代码似乎按预期工作,但并没有像我希望的那样显著提高速度,大约为120毫秒。这可能是因为它还需要针对每个项目遍历整个列表,但我不确定如何避免这种情况并仍然完成任务。
我知道这可能看起来像过早优化,但我的列表很容易达到100万+,而这个方法是我应用程序的关键部分,影响其他所有内容的时间安排。
你有没有看到我可以进一步优化这段代码的方法?也许使用某种高级Predicate?或者完全不同的方法?
编辑: 感谢您所有的建议,我能够想出一个明显更快的解决方案:
public synchronized Set<String> listMatching(List<String> allStrings) {
Set<String> allItems = new HashSet<>();
Set<String> duplicates = allStrings.stream()
.filter(string -> !allItems.add(string))
.collect(Collectors.toSet());
return duplicates;
}
在相同的条件下运行,这可以在<5毫秒内通过我的列表。 如果我需要知道计数,所有的HashMap建议都将是很好的选择。不确定为什么Collections.frequency()方法不使用该技术。