irpas技术客

Java中List集合对象去重及按属性去重_liuerchong_java list 根据属性去重

网络投稿 5448

集合元素整体去重

以List中的String类型以集合元素对象为单位整体去重为例。如果List放入的是Object对象,需要你去实现对象的equals和hashCode方法,去重的代码实现方法和List去重是一样的。

先把List数据放入Set,因为Set数据结构本身具有去重的功能,所以再将SET转为List之后就是去重之后的结果。这种方法在去重之后会改变原有的List元素顺序,因为HashSet本身是无序的,而TreeSet排序也不是List种元素的原有顺序。 @Test void testRemove1() { /*Set<String> set = new HashSet<>(list); List<String> newList = new ArrayList<>(set);*/ //去重并排序的方法(如果是字符串,按字母表排序。如果是对象,按Comparable接口实现排序) //List<String> newList = new ArrayList<>(new TreeSet<>(list)); //简写的方法 List<String> newList = new ArrayList<>(new HashSet<>(list)); System.out.println( "去重后的集合: " + newList); } 用stream方法将集合转换成流,然后distinct去重,最后在将Stream流collect收集为List。 @Test void testRemove2() { List<String> newList = list.stream().distinct().collect(Collectors.toList()); System.out.println( "去重后的集合: " + newList); } 利用set.add(T),如果T元素已经存在集合中,就返回false。利用这个方法进行是否重复的数据判断,如果不重复就放入一个新的newList中,这个newList就是最终的去重结果 //三个集合类list、newList、set,能够保证顺序 @Test void testRemove3() { Set<String> set = new HashSet<>(); List<String> newList = new ArrayList<>(); for (String str :list) { if(set.add(str)){ //重复的话返回false newList.add(str); } } System.out.println( "去重后的集合: " + newList); } 使用newList.contains(T)方法,在向新的List添加数据的时候判断这个数据是否已经存在,如果存在就不添加,从而达到去重的效果。 //优化 List、newList、set,能够保证顺序 @Test void testRemove4() { List<String> newList = new ArrayList<>(); for (String cd:list) { if(!newList.contains(cd)){ //主动判断是否包含重复元素 newList.add(cd); } } System.out.println( "去重后的集合: " + newList); } 按照集合元素对象属性去重

实际的工作中,按照集合元素对象整体去重的应用的比较少,更多的是要求我们按照元素对象的某些属性进行去重。

为TreeSet实现Comparator接口,如果我们希望按照Player的name属性进行去重,就去在Comparator接口中比较name。下文中写了两种实现Comparator接口方法:

lambda表达式:(o1, o2) -> o1.getName().compareTo(o2.getName()) 方法引用:Comparator.comparing(Player::getName)

@Test void testRemove5() { //Set<Player> playerSet = new TreeSet<>((o1, o2) -> o1.getName().compareTo(o2.getName())); Set<Player> playerSet = new TreeSet<>(Comparator.comparing(Player::getName)); playerSet.addAll(playerList); /*new ArrayList<>(playerSet).forEach(player->{ System.out.println(player.toString()); });*/ //将去重之后的结果打印出来 new ArrayList<>(playerSet).forEach(System.out::println); } 首先用stream()把list集合转换成流,然后用collect及toCollection把流转换成集合 @Test void testRemove6() { List<Player> newList = playerList.stream().collect(Collectors .collectingAndThen( Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(Player::getName))), ArrayList::new)); newList.forEach(System.out::println); } filter方法

首先我们定义一个谓词Predicate用来过滤,过滤的条件是distinctByKey。谓词返回ture元素保留,返回false元素被过滤掉。 当然我们的需求是过滤掉重复元素。我们去重逻辑是通过map的putIfAbsent实现的。putIfAbsent方法添加键值对,如果map集合中没有该key对应的值,则直接添加,并返回null,如果已经存在对应的值,则依旧为原来的值。 如果putIfAbsent返回null表示添加数据成功(不重复),如果putIfAbsent返回value(value==null :false),则满足了distinctByKey谓词的条件元素被过滤掉。

@Test void testRemove7() { List<Player> newList = new ArrayList<>(); playerList.stream().filter(distinctByKey(p -> p.getName())) //filter保留true的值 .forEach(newList::add); newList.forEach(System.out::println); } static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) { Map<Object,Boolean> seen = new ConcurrentHashMap<>(); //putIfAbsent方法添加键值对,如果map集合中没有该key对应的值,则直接添加,并返回null,如果已经存在对应的值,则依旧为原来的值。 //如果返回null表示添加数据成功(不重复),不重复(null==null :TRUE) return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null; }

种方法虽然看上去代码量增大了,但是distinctByKey谓词方法只需要被定义一次,就可以无限复用。

利用多个属性去重 @Test void testRemove8() { Set<Player> playerSet = new TreeSet<>(Comparator.comparing(o -> (o.getName() + "" + o.getAge()))); playerSet.addAll(playerList); new ArrayList<>(playerSet).forEach(System.out::println); }


1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,会注明原创字样,如未注明都非原创,如有侵权请联系删除!;3.作者投稿可能会经我们编辑修改或补充;4.本站不提供任何储存功能只提供收集或者投稿人的网盘链接。

标签: #JAVA #list #根据属性去重 #Testvoid