【问题标题】:Find elements in a list that are not present in another list using java 8使用java 8查找列表中不存在于另一个列表中的元素
【发布时间】:2019-08-23 07:07:55
【问题描述】:

我有 2 个列表。要求是根据条件过滤掉list1中不在list2中的元素。

  Class Fighter
  {
    String name;
    String address;
  }     
  List<Fighter> pairs1 = new ArrayList();
    pairs1.add(new Fighter("a", "a"));
    pairs1.add(new Fighter("b", "a"));

    List<Fighter> pairs2 = new ArrayList();
    pairs2.add(new Fighter("a", "c"));
    pairs2.add(new Fighter("a", "d"));
    Set<Fighter> finalValues = new HashSet<>();


    finalValues = pairs1.stream().filter(firstList -> 
   pairs2.stream().noneMatch(secondList -> 
   firstList.getName().equals(secondList.getName())
            && firstList.getName().equals(secondList.getName()))).collect(Collectors.toSet());

    System.out.println(finalValues);

预期输出:a=a, b=a

解释:list1 中的元素不在 list2 中

上面的代码没有给出预期的输出。请让我知道如何更正上述流代码以获得输出

【问题讨论】:

  • 最简单的方法是实现一个包含两个属性的equals(带有hashcode),然后在另一个列表中简单地执行contains。同样在当前上下文中noneMatch(secondList -&gt; firstList.getName().equals(secondList.getName()) &amp;&amp; firstList.getAddress().equals(secondList.getAddress())) 应该修复它。

标签: java lambda java-8 java-stream


【解决方案1】:

首先覆盖 Fighter 类中的 equals 和 hashcode 方法。

@Override
public boolean equals(Object o) {
    if (o == this)
        return true;
    if (!(o instanceof Fighter))
        return false;
    Fighter f = (Fighter) o;
    return f.name.equals(name) && f.address.equals(address);
}

@Override
public int hashCode() {
    int result = name.hashCode();
    result = 31 * result + address.hashCode();
    return result;
}

然后从pairs2创建一个Set。最后使用它的 contains 方法来获取设置的差异。这是它的外观,

Set<Fighter> pairs2Set = new HashSet<>(pairs2);
Set<Fighter> setDiff = pairs1.stream()
    .filter(f -> !pairs2Set.contains(f))
    .collect(Collectors.toSet());

【讨论】:

    【解决方案2】:

    在过滤器内匹配时不要使用地址。

    List<Fighter> res = pairs1.stream()
                        .filter(f -> !pairs2.stream()
                                            .anyMatch(s -> f.getName().equals(s.getName())
                                                      && f.getAddress().equals(s.getAddress())))
                       .collect(Collectors.toList());
    

    这里根据条件过滤第一个列表的元素,如果包含在第二个列表中。

    更好的方法

    使用 List 的 contains 方法

    List<Fighter> res = pairs1.stream()
                                .filter(e -> !pairs2.contains(e)) 
                                .collect(Collectors.toList());
    

    你需要重写 Fighter 类中的equals() 方法。 contains() 方法您将使用equals() 方法来评估两个对象是否相同。

    @Override
    public boolean equals(Object o) {
        if (o == this)
            return true;
        if (!(o instanceof Fighter))
            return false;
        Fighter f = (Fighter) o;
        return f.name.equals(name) && f.address.equals(address);
    }
    

    但是使用 Set 会更快。查看类似problem solution using Set

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-01-06
      • 1970-01-01
      • 1970-01-01
      • 2011-08-17
      • 2019-03-25
      • 1970-01-01
      • 2017-04-28
      相关资源
      最近更新 更多