Stream流根据属性去重
List根据属性去重
创建一个user集合
User user1 = new User("user1", 18, "AAA");
User user2 = new User("user2", 18, "BBB");
User user3 = new User("user3", 18, "AAA");
User user4 = new User("user4", 75, "CCC");
User user5 = new User("user5", 35, "AAA");
ArrayList<User> list = new ArrayList<>();
list.add(user1);
list.add(user2);
list.add(user3);
list.add(user4);
list.add(user5);
自定义Predict函数,使用filter()
写一个Predict
public class DistinctKeyUtil {
public static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
ConcurrentHashMap<Object, Boolean> map = new ConcurrentHashMap<>();
return t -> map.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
}
}
使用filter方法
/**
* 写一个Predict进行属性过滤
*/
//先过滤age在过滤hobby
List<User> result = list.stream()
.filter(DistinctKeyUtil.distinctByKey(n -> n.getAge()))
.filter(DistinctKeyUtil.distinctByKey(n -> n.getHobby()))
.collect(Collectors.toList());
result.forEach(System.out::println);
结果:
User{name='user1', age=18, hobby='AAA'}
User{name='user4', age=75, hobby='CCC'}
小结:
实质上是将每个元素都放到distinctByKey()中的ConcurrentHashMap作为key进行过滤,如果key不存在那么就加上去,如果已经存在了就不加。所以这种方式的过滤只保留第一个重复元素。
利用TreeSet
//过滤age
ArrayList<User> result2 = list.stream().collect(
Collectors.collectingAndThen(
Collectors.toCollection(
() -> new TreeSet<>(Comparator.comparing(o -> o.getAge()))), ArrayList::new));
result2.forEach(System.out::println);
结果与上面的一样
同时过滤两个属性
//age和hobby一起过滤
ArrayList<User> result1 = list.stream().collect(
Collectors.collectingAndThen(
Collectors.toCollection(
() -> new TreeSet<>(Comparator.comparing(o -> o.getHobby() + ";" + o.getAge()))), ArrayList::new)
);
result1.forEach(System.out::println);
结果:
User{name='user1', age=18, hobby='AAA'}
User{name='user5', age=35, hobby='AAA'}
User{name='user2', age=18, hobby='BBB'}
User{name='user4', age=75, hobby='CCC'}
小结:
TreeSet存储唯一的元素,并且按升序对元素进行排序。
Map:保证Key的唯一性
/**
* map 根据某属性过滤
*/
// Function.identity() 相等于 o->o
Map<String, User> map1 = list.stream().collect(Collectors.toMap(User::getHobby, Function.identity(), (t1, t2) -> t1));
Set<Map.Entry<String, User>> entries1 = map1.entrySet();
entries1.forEach(System.out::println);
结果:
AAA=User{name='user1', age=18, hobby='AAA'}
CCC=User{name='user4', age=75, hobby='CCC'}
BBB=User{name='user2', age=18, hobby='BBB'}
小结:
map可以选择保留重复属性中的前一条数据还是后一条:(t1, t2) -> t1)