在Java 8中,我如何使用流API通过检查每个对象的属性的清晰度来过滤一个集合?
例如,我有一个Person对象列表,我想删除同名的人,
persons.stream().distinct();
将对Person对象使用默认的相等性检查,所以我需要这样的东西,
persons.stream().distinct(p -> p.getName());
不幸的是,distinct()方法没有这样的重载。如果不修改Person类内部的相等检查,是否可以简洁地做到这一点?
在Java 8中,我如何使用流API通过检查每个对象的属性的清晰度来过滤一个集合?
例如,我有一个Person对象列表,我想删除同名的人,
persons.stream().distinct();
将对Person对象使用默认的相等性检查,所以我需要这样的东西,
persons.stream().distinct(p -> p.getName());
不幸的是,distinct()方法没有这样的重载。如果不修改Person类内部的相等检查,是否可以简洁地做到这一点?
当前回答
你能写的最简单的代码:
persons.stream().map(x-> x.getName()).distinct().collect(Collectors.toList());
其他回答
有一种更简单的方法,使用带有自定义比较器的TreeSet。
persons.stream()
.collect(Collectors.toCollection(
() -> new TreeSet<Person>((p1, p2) -> p1.getName().compareTo(p2.getName()))
));
你能写的最简单的代码:
persons.stream().map(x-> x.getName()).distinct().collect(Collectors.toList());
处理null的顶部答案的变体:
public static <T, K> Predicate<T> distinctBy(final Function<? super T, K> getKey) {
val seen = ConcurrentHashMap.<Optional<K>>newKeySet();
return obj -> seen.add(Optional.ofNullable(getKey.apply(obj)));
}
在我的测试中:
assertEquals(
asList("a", "bb"),
Stream.of("a", "b", "bb", "aa").filter(distinctBy(String::length)).collect(toList()));
assertEquals(
asList(5, null, 2, 3),
Stream.of(5, null, 2, null, 3, 3, 2).filter(distinctBy(x -> x)).collect(toList()));
val maps = asList(
hashMapWith(0, 2),
hashMapWith(1, 2),
hashMapWith(2, null),
hashMapWith(3, 1),
hashMapWith(4, null),
hashMapWith(5, 2));
assertEquals(
asList(0, 2, 3),
maps.stream()
.filter(distinctBy(m -> m.get("val")))
.map(m -> m.get("i"))
.collect(toList()));
我遇到了一种情况,我应该根据2个键从列表中获得不同的元素。 如果您希望基于两个键或组合键进行区分,请尝试此操作
class Person{
int rollno;
String name;
}
List<Person> personList;
Function<Person, List<Object>> compositeKey = personList->
Arrays.<Object>asList(personList.getName(), personList.getRollno());
Map<Object, List<Person>> map = personList.stream().collect(Collectors.groupingBy(compositeKey, Collectors.toList()));
List<Object> duplicateEntrys = map.entrySet().stream()`enter code here`
.filter(settingMap ->
settingMap.getValue().size() > 1)
.collect(Collectors.toList());
你可以使用groupingBy collector:
persons.collect(Collectors.groupingBy(p -> p.getName())).values().forEach(t -> System.out.println(t.get(0).getId()));
如果你想有另一个流,你可以使用这个:
persons.collect(Collectors.groupingBy(p -> p.getName())).values().stream().map(l -> (l.get(0)));