【问题标题】:Comparing two big lists (more than 100k) in java比较java中的两个大列表(超过100k)
【发布时间】:2019-11-06 22:30:22
【问题描述】:

我想在 java 中更快地比较两个大小不同的大字符串列表。我想知道有没有更好的方法来提高性能。

我在

中看到了性能问题
List<String> list1 = 100k records 
List<String> list2 = 10 million records;

#method1 used removeAll
list1.removeAll(list2);

method2 used java8 streams
List<String> unavailable = list1.stream()
                    .filter(e -> (list2.stream()
                            .filter(d -> d.equals(e))
                            .count())<1)
                            .collect(Collectors.toList());

注意:我正在尝试获取在 list1 中但在 list2 中不存在的记录。

【问题讨论】:

  • “比较”是什么意思?
  • 西方世界的大多数人都不知道 10 万意味着 10 万。
  • 我相信您的意思是 10 万,其中 100 万 = 100 万。除此之外,流并不比使用for 循环迭代快。还有一点要补充的是,您想通过比较来做什么?
  • 是的,您的要求还不清楚。你打算达到什么目的。您的方法 1 和方法 2 会产生非常不同的结果。第一个修改 list1,第二个创建一个新列表。那么:你想要达到的具体目标是什么?
  • 您似乎正在尝试确保第一个列表中的所有项目都在第二个列表中?在这种情况下,您应该从第二个列表创建一个集合并使用contains

标签: java collections java-8 stream java-stream


【解决方案1】:
List<String> unavailable = list1.stream()
                                .filter(e -> !list2.contains(e))
                                .collect(Collectors.toList());

(或)

List<String> unavailable = list1.stream() 
                                .filter(not(list2::contains)) 
                                .collect(Collectors.toList());

如下创建谓词

public static <T> Predicate<T> not(Predicate<T> t) {
        return t.negate();
    }

【讨论】:

  • Java 11 已经有 Predicate.not() 但除此之外,您的回答将净提高性能。
【解决方案2】:

要提高性能,您唯一能做的就是使用Sets 而不是Lists,因为Set.contains()O(1)。但因此您不应该关心列表中的重复项。

如果您不关心项目的顺序,请使用HashSet,否则使用LinkedHashSet。如果使用 Set.removeAll()Stream.filter(),使用集合几乎无关紧要,因为 removeAll() 在内部使用 contains()

所以如果你需要一套新的并且不想碰原来的,你也可以使用它:

Set<String> set2 = new HashSet<>(list2);
Set<String> unavailable = list1.stream()
        .filter(e -> !set2.contains(e))
        .collect(Collectors.toSet());

如果您想要一个列表作为结果,请改用Collectors.toList()

Set<String> set2 = new HashSet<>(list2);
List<String> unavailable = list1.stream()
        .filter(e -> !set2.contains(e))
        .collect(Collectors.toList());

如果您只想从 list1 中删除项目,请使用此选项:

Set<String> set2 = new HashSet<>(list2);
list1.removeAll(set2);

甚至更短:

list1.removeAll(new HashSet<>(list2));

【讨论】:

  • 谢谢@Samuel Philipp,我看到现在使用 set 的性能有了很大提高。
猜你喜欢
  • 1970-01-01
  • 2011-02-15
  • 1970-01-01
  • 2013-06-10
  • 1970-01-01
  • 2016-05-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多