【问题标题】:Java stream remove duplicate list of objects of list propertyJava流删除列表属性对象的重复列表
【发布时间】:2021-05-05 16:32:24
【问题描述】:

我有对象列表说

class Address {

  private String houseno;
  private String street;
  private String city;
  private String landmark;
  private String country;
}

class Obj1 {
  private String id;
  private String name;
  private String mail;
  private List<Address> address;
}

List<Obj1> obj1s = new ArrayList<>();

我有一个 obj1 列表,其中包含我需要使用一些过滤器提取的数据。我需要检索城市和国家不能重复的所有 obj1。如果地址列表中的任何一个包含与其他 obj1 相同的城市和国家/地区,那么我不需要在该列表中。

我正在尝试相同的方法,但不起作用。

obj1s.stream().collect(Collectors.toMap((obj1.getAddress()), p -> p, (p, q) -> p)).values();

它可以通过循环和 if else 条件来完成,但要寻找 java 流和更好的解决方案。有什么好办法解决吗?

city+country 可以在所有 obj1 中重复。在地址列表中,它将是唯一的

【问题讨论】:

  • 如果城市+国家在obj1s 中的所有Obj1s 中重复,或者在Obj1 对象中的所有地址中重复?
  • @ernest_k,可以跨obj1s复制
  • 旁白:如果将Obj1 重命名为User,这个问题就会变得更有意义。疑问:如果Obj1 aObj1 b 的任何Address 具有相同的城市+国家,您不希望这两个成为最终结果的一部分吗?
  • @Naman,我想要一个成为结果的一部分,而不是重复的
  • 为了清楚输入和所需的输出,最好将您的方法与您所说的循环和条件分享。

标签: java java-stream


【解决方案1】:

我们需要像“distinct”这样的东西,它有点像有状态的过滤器。因此,我们可以创建自己的过滤器,具有自己的先前看到的城市/国家对的状态。这可以通过使用带有自己的 Set 的过滤器来实现:

public static <T> Predicate<T> distinctAddress() {
    Set<Object> seen = ConcurrentHashMap.newKeySet();
    return t -> {
        boolean r = ((Obj1)t).getAddress().stream().map((a) -> seen.contains(new AbstractMap.SimpleImmutableEntry<>(a.getCity(), a.getCountry()))).anyMatch((b) -> b);
        ((Obj1)t).getAddress().stream().forEach((a) -> seen.add(new AbstractMap.SimpleImmutableEntry<>(a.getCity(), a.getCountry())));
        return !r;
    };
}

List<Obj1> list = obj1s.stream().filter(distinctAddress()).collect(Collectors.toList());

编辑: 我刚刚意识到您提到地址在地址列表中始终是唯一的。在这种情况下,您可以这样缩短谓词(因为由于相同的列表,您不会在 Set 中拥有它):

public static <T> Predicate<T> distinctAddress() {
    Set<Object> seen = ConcurrentHashMap.newKeySet();
    return t -> ((Obj1)t).getAddress().stream().map((a) -> seen.add(new AbstractMap.SimpleImmutableEntry<>(a.getCity(), a.getCountry()))).filter((e) -> e).count() > 0;
}

List<Obj1> list = obj1s.stream().filter(distinctAddress()).collect(Collectors.toList());

【讨论】:

    【解决方案2】:

    你可以这样做:

    Map<String, List<Obj1>> result= objs.stream()
                .flatMap(obj -> {
    
                            Map<String, Obj1> map = obj.address.stream()
                                    .map(address -> address.country + address.city)
                                    .collect(Collectors.toMap(String::valueOf, str -> obj));
    
                            return map.entrySet().stream();
                        }
    
                ).collect(Collectors.groupingBy(
                        Map.Entry::getKey,
                        Collectors.mapping(Map.Entry::getValue, Collectors.toList()))
                );
    

    它返回一个映射,它的键是由 address.name 和 address.country 为每个地址生成的,它的值是当前具有该地址的 Obj1 对象的列表。

    请在测试前确保每个地址列表都有独特的元素

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-10-26
      相关资源
      最近更新 更多