Java中List集合对象去重及按属性去重的8种方法
一、本文描述
这一篇文章写一下List集合元素去重的8种方法,实际上通过灵活的运用、排列组合不一定是8种,可能有18种方法。对象元素整体去重的4种方法按照对象属性去重的4种方法
为了在下文中进行测试内容讲解,我们先做一些初始化数据publicclassListRmDuplicate{privateListStringlist;privateListPlayerplayerList;BeforeEachpublicvoidsetup(){listnewArrayList();list。add(kobe);list。add(james);list。add(curry);list。add(zimug);list。add(zimug);playerListnewArrayList();playerList。add(newPlayer(kobe,10000));科比万岁playerList。add(newPlayer(james,32));playerList。add(newPlayer(curry,30));playerList。add(newPlayer(zimug,27));注意这里名字重复playerList。add(newPlayer(zimug,18));注意这里名字和年龄重复playerList。add(newPlayer(zimug,18));注意这里名字和年龄重复}}
Player对象就是一个普通的java对象,有两个成员变量name与age,实现了带参数构造函数、toString、equals和hashCode方法、以及GETSET方法。二、集合元素整体去重
下文中四种方法对List中的String类型以集合元素对象为单位整体去重。如果你的List放入的是Object对象,需要你去实现对象的equals和hashCode方法,去重的代码实现方法和List去重是一样的。第一种方法
是大家最容易想到的,先把List数据放入Set,因为Set数据结构本身具有去重的功能,所以再将SET转为List之后就是去重之后的结果。这种方法在去重之后会改变原有的List元素顺序,因为HashSet本身是无序的,而TreeSet排序也不是List种元素的原有顺序。TestvoidtestRemove1(){SetStringsetnewHashSet(list);ListStringnewListnewArrayList(set);去重并排序的方法(如果是字符串,按字母表排序。如果是对象,按Comparable接口实现排序)ListStringnewListnewArrayList(newTreeSet(list));简写的方法ListStringnewListnewArrayList(newHashSet(list));System。out。println(去重后的集合:newList);}
控制台打印结果如下:去重后的集合:〔kobe,james,zimug,curry〕第二种方法
使用就比较简单,先用stream方法将集合转换成流,然后distinct去重,最后在将Stream流collect收集为List。
控制台打印结果如下:去重后的集合:〔kobe,james,curry,zimug〕第三种方法
这种方法利用了set。add(T),如果T元素已经存在集合中,就返回false。利用这个方法进行是否重复的数据判断,如果不重复就放入一个新的newList中,这个newList就是最终的去重结果三个集合类list、newList、set,能够保证顺序TestvoidtestRemove3(){SetStringsetnewHashSet();ListStringnewListnewArrayList();for(Stringstr:list){if(set。add(str)){重复的话返回falsenewList。add(str);}}System。out。println(去重后的集合:newList);}
控制台打印结果和第二种方法一致。第四种方法
这种方法已经脱离了使用Set集合进行去重的思维,而是使用newList。contains(T)方法,在向新的List添加数据的时候判断这个数据是否已经存在,如果存在就不添加,从而达到去重的效果。优化List、newList、set,能够保证顺序TestvoidtestRemove4(){ListStringnewListnewArrayList();for(Stringcd:list){if(!newList。contains(cd)){主动判断是否包含重复元素newList。add(cd);}}System。out。println(去重后的集合:newList);}
控制台打印结果和第二种方法一致。三、按照集合元素对象属性去重
其实在实际的工作中,按照集合元素对象整体去重的应用的还比较少,更多的是要求我们按照元素对象的某些属性进行去重。
看到这里请大家回头去看一下上文中,构造的初始化数据playerList,特别注意其中的一些重复元素,以及成员变量重复。第一种方法
为TreeSet实现Comparator接口,如果我们希望按照Player的name属性进行去重,就去在Comparator接口中比较name。下文中写了两种实现Comparator接口方法:lambda表达式:(o1,o2)o1。getName()。compareTo(o2。getName())方法引用:Comparator。comparing(Player::getName)TestvoidtestRemove5(){SetPlayerplayerSetnewTreeSet((o1,o2)o1。getName()。compareTo(o2。getName()));SetPlayerplayerSetnewTreeSet(Comparator。comparing(Player::getName));playerSet。addAll(playerList);newArrayList(playerSet)。forEach(player{System。out。println(player。toString());});将去重之后的结果打印出来newArrayList(playerSet)。forEach(System。out::println);}
输出结果如下:三个zimug因为name重复,另外两个被去重。但是因为使用到了TreeSet,list中元素被重新排序。Player{namecurry,age30}Player{namejames,age32}Player{namekobe,age10000}Player{namezimug,age27}第二种方法
这种方法是网上很多的文章中用来显示自己很牛的方法,但是在笔者看来有点脱了裤子放屁,多此一举。既然大家都说有这种方法,我不写好像我不牛一样。我为什么说这种方法是脱了裤子放屁?首先用stream()把list集合转换成流然后用collect及toCollection把流转换成集合然后剩下的就和第一种方法一样了
前两步不是脱了裤子放屁么?看看就得了,实际应用意义不大,但是如果是为了学习Stream流的使用方法,搞出这么一个例子还是有可取之处的。TestvoidtestRemove6(){ListPlayernewListplayerList。stream()。collect(Collectors。collectingAndThen(Collectors。toCollection(()newTreeSet(Comparator。comparing(Player::getName))),ArrayList::new));newList。forEach(System。out::println);}
控制台打印输出和第一种方法一样。第三种方法
这种方法也是笔者建议大家使用的一种方法,咋一看好像代码量更大了,但实际上这种方法是应用比较简单的方法。
Predicate(有人管这个叫断言,从英文的角度作为名词可以翻译为谓词,作为动词可以翻译为断言)。谓词就是用来修饰主语的,比如:喜欢唱歌的小鸟,喜欢唱歌就是谓词,用来限定主语的范围。所以我们这里是用来filter过滤的,也是用来限制主语范围的,所以我认为翻译为谓词更合适。随便吧,看你怎么觉得怎么理解合理、好记,你就怎么来。首先我们定义一个谓词Predicate用来过滤,过滤的条件是distinctByKey。谓词返回ture元素保留,返回false元素被过滤掉。当然我们的需求是过滤掉重复元素。我们去重逻辑是通过map的putIfAbsent实现的。putIfAbsent方法添加键值对,如果map集合中没有该key对应的值,则直接添加,并返回null,如果已经存在对应的值,则依旧为原来的值。如果putIfAbsent返回null表示添加数据成功(不重复),如果putIfAbsent返回value(valuenull:false),则满足了distinctByKey谓词的条件元素被过滤掉。
这种方法虽然看上去代码量增大了,但是distinctByKey谓词方法只需要被定义一次,就可以无限复用。TestvoidtestRemove7(){ListPlayernewListnewArrayList();playerList。stream()。filter(distinctByKey(pp。getName()))filter保留true的值。forEach(newList::add);newList。forEach(System。out::println);}staticTPredicateTdistinctByKey(Functionlt;?superT,?keyExtractor){MapObject,BooleanseennewConcurrentHashMap();putIfAbsent方法添加键值对,如果map集合中没有该key对应的值,则直接添加,并返回null,如果已经存在对应的值,则依旧为原来的值。如果返回null表示添加数据成功(不重复),不重复(nullnull:TRUE)returntseen。putIfAbsent(keyExtractor。apply(t),Boolean。TRUE)null;}
输出结果如下:三个zimug因为name重复,另外两个被去重。并且没有打乱List的原始顺序Player{namekobe,age10000}Player{namejames,age32}Player{namecurry,age30}Player{namezimug,age27}第四种方法
第四种方法实际上不是新方法,上面的例子都是按某一个对象属性进行去重,如果我们想按照某几个元素进行去重,就需要对上面的三种方法进行改造。
我只改造其中一个,另外几个改造的原理是一样的,就是把多个比较属性加起来,作为一个String属性进行比较。TestvoidtestRemove8(){SetPlayerplayerSetnewTreeSet(Comparator。comparing(o(o。getName()o。getAge())));playerSet。addAll(playerList);newArrayList(playerSet)。forEach(System。out::println);}总结
到此这篇关于Java中List集合对象去重及按属性去重的8种方法的文章就介绍到这了
5000万元中央彩票公益金刷新乡村颜值,游客一下高速即入景区暖阳高照,车来车往。1月9日,走进神农架林区松柏镇古水村白鱼洞片区,几个工地一片忙碌,工人们正在打桩砌坎浇筑混凝土。抢抓晴好天气,加快项目建设。松柏镇中彩建设项目负责人王爱华说,白
省市重点项目超进度完成,中山科技创新园等项目动工中山奋进这一年开栏语2022年是中山市高质量发展的关键之年,全市上下以改革开路,突围破局,在产业发展城市建设社会治理等领域均取得新进展。即日起,南方中山频道推出中山奋进这一年系列报道,看中山20
这座欧洲屋脊为中国游客准备的兔年惊喜亮相啦!来源新华社中国农历新年将至,有欧洲屋脊美誉的瑞士少女峰热切期待中国游客。新华社记者了解到,少女峰专门为中国游客准备的兔年惊喜冰雕兔,于当地时间17日正式亮相。2023年新春快乐,兔
汕头南澳山海之间煌煌人文南澳岛横卧于山海之间栏目统筹魏琴文曾柯权蚁璐雅魏琴陈纪中图蚁璐雅南澳县委宣传部南澳文体旅游局挥别民族英雄文天祥留下名篇的珠海万山群岛,羊城晚报大美岭南栏目第34站走进广东省唯一海岛
打卡良庆(21)打卡南宁之夜南宁之夜坐落于南宁五象新区,东邻五象湖中央公园,西邻广西美术馆。是广西首个集娱乐,演出,美食,购物,沉浸式体验于一体的文旅步行街。南宁之夜街区一期总长约600多米,地标性商业街区3
翰墨飘香迎兔年百福浓情进万家开门纳福迎新年公益活动现场。红网时刻新闻1月17日讯(记者余雅琴通讯员刘慧)兔年新春即将到来之际,为进一步弘扬中华优秀传统文化,营造欢乐祥和的喜悦氛围,1月17日上午,湖南烈士公园
花潮人海喜洋洋长街涌动庆良宵行花街成为最具特色的广府年俗。(资料图片)视觉中国荔湾水上花市视觉中国骑膊马,行花街。视觉中国在广州人心里,爱花就是爱生活。民国时期的广州花市。1957年1月31日广州日报刊登的花
打卡游园赏花灯来这里感受兔年的流光溢彩嘉定的小伙伴们,看过来南翔古猗园的春节花灯已然点亮快跟着小嘉的镜头一起去先睹为快吧非遗花灯的流光溢彩与江南园林的朴素淡雅相辅相成,园内三处寻春之路(儿童园区域趣味灯景逸野堂至水木明
苹果摊牌了?iPhone电池更换全系涨价,人民网点赞小米11从阴谋到阳谋,苹果终于开始摊牌了。不可否认,苹果iPhone在很多方面都要领先安卓手机不少,但这掩盖不了苹果吃相越来越难看的事实。前两年,库克以环保为由取消了iPhone的附赠充电
2023年,我希望!2023,我希望家人都是健健康康的,家庭都是和和睦睦的,每天都是开开心心的,一直都是快快乐乐的!2023,我希望生活都是大富大贵的,日子都是安安稳稳的,心想都是可以事成的,愿望都是
坚守初心,一展芳华初心在最开始的时候,往往简单朴素。但是它会慢慢长大,就仿佛站在零的起点慢慢绵延成很长很长的道路。到最后我们会发现,所谓初心,就是在所有愿望誓言和梦想当中离自己本心最近的那颗心。题记