Java中List集合对象去重及按属性去重七种方法

集合元素整体去重

—本人常用list对象去重

  1. 单条件属性:
//实体对象
 /** id */
 @Data
public class MyXscx extends BaseEntity implements Serializable
{
    @ExcelIgnore
    private Long id;
    /** 序号 */
    @Excel(name = "序号")
    @ExcelProperty(index = 0)
    private String xh; 
    ........
    //添加方法:根据id升序排列
    public int compareToAsc(MyXscx o) {
        return (int) (this.id - o.id);
    }
    //添加方法:根据id降序排列
    public int compareToDesc(MyXscx o) {
        return (int) (o.id-this.id);
    }
 }
//去重(无序)
List<> firstMenu=myXscxList.stream().collect(Collectors.collectingAndThen(Collectors.toCollection(()->new TreeSet<>(Comparator.comparing(MyXscx::getType))), ArrayList::new));
//排序
 Collections.sort(firstMenu,MyXscx::compareToAsc);

2.多条件2去重

//只需(MyXscx::getType)改为(o->o.getType()+";"+o.getZqlb()
List<MyXscx> secondMenus=firstMenu.stream().collect(Collectors.collectingAndThen(Collectors.toCollection(()->new TreeSet<>(Comparator.comparing(o->o.getType()+";"+o.getZqlb()))), ArrayList::new));
        Collections.sort(secondMenus,MyXscx::compareToAsc);

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

1、第一种方法

先把List数据放入Set,因为Set数据结构本身具有去重的功能,所以再将SET转为List之后就是去重之后的结果。这种方法在去重之后会改变原有的List元素顺序,因为HashSet本身是无序的,而TreeSet排序也不是List种元素的原有顺序。

 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);

2、第二种方法

用stream方法将集合转换成流,然后distinct去重,最后在将Stream流collect收集为List。

@Test
void testRemove2() {
 List<String> newList = list.stream().distinct().collect(Collectors.toList());
 
 System.out.println( "去重后的集合: " + newList);
}

3、第三种方法

利用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);
}

4、第四种方法

使用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);
}

5、第五种方法

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

为TreeSet实现Comparator接口,如果我们希望按照Player的name属性进行去重,就去在Comparator接口中比较name。下文中写了两种实现Comparator接口方法:
lambda表达式:(o1, o2) -> o1.getName().compareTo(o2.getName())
方法引用:Comparator.comparing(Player::getName)

@Test
void testRemove5() {
 //Set 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);
}

6、第六种方法

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谓词方法只需要被定义一次,就可以无限复用。

7、第七种方法

利用多个属性去重

@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);
}

你可能感兴趣的:(java开发学习,java)