Java 8 按属性区分

新手上路,请多包涵

在 Java 8 中,如何通过检查每个对象的属性的独特性来使用 Stream API 过滤集合?

例如,我有一个 Person 对象的列表,我想删除同名的人,

 persons.stream().distinct();

将对 Person 对象使用默认相等检查,所以我需要类似的东西,

 persons.stream().distinct(p -> p.getName());

不幸的是 distinct() 方法没有这样的重载。如果不修改 Person 类中的相等检查,是否可以简洁地做到这一点?

原文由 RichK 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 626
2 个回答

考虑 distinct 是一个 _有状态的过滤器_。这是一个返回谓词的函数,该谓词维护先前看到的状态,并返回是否第一次看到给定元素:

 public static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
    Set<Object> seen = ConcurrentHashMap.newKeySet();
    return t -> seen.add(keyExtractor.apply(t));
}

然后你可以写:

 persons.stream().filter(distinctByKey(Person::getName))

请注意,如果流是有序的并且并行运行,这将保留重复项中的 任意 元素,而不是第一个元素,就像 distinct() 那样。

(这与 我对这个问题的回答 基本相同: Java Lambda Stream Distinct() on absolute key?

原文由 Stuart Marks 发布,翻译遵循 CC BY-SA 3.0 许可协议

另一种方法是使用名称作为键将人员放置在地图中:

 persons.collect(Collectors.toMap(Person::getName, p -> p, (p, q) -> p)).values();

请注意,保留的 Person 将在重名的情况下第一个出现。

原文由 wha‘eve’ 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题