亚洲精品久久久中文字幕-亚洲精品久久片久久-亚洲精品久久青草-亚洲精品久久婷婷爱久久婷婷-亚洲精品久久午夜香蕉

您的位置:首頁技術(shù)文章
文章詳情頁

Java中List集合對象去重及按屬性去重的8種方法

瀏覽:2日期:2022-08-25 13:21:03

Java中List集合對象去重及按屬性去重的8種方法

最近在寫一些關(guān)于java基礎(chǔ)的文章,但是我又不想按照教科書的方式去寫知識點(diǎn)的文章,因?yàn)橐饬x不大。基礎(chǔ)知識太多了,如何將這些知識歸納總結(jié),總結(jié)出優(yōu)缺點(diǎn)或者是使用場景才是對知識的升華。所以我更想把java相關(guān)的基礎(chǔ)知識進(jìn)行穿針引線,進(jìn)行整體上的總結(jié)。

總結(jié)java中創(chuàng)建并寫文件的5種方式 總結(jié)java從文件中讀取數(shù)據(jù)的6種方法 總結(jié)java創(chuàng)建文件夾的4種方法及其優(yōu)缺點(diǎn) 總結(jié)java中刪除文件或文件夾的7種方法 總結(jié)java中文件拷貝剪切的5種方式

比如之前我已經(jīng)寫了上面的這些內(nèi)容,如果對java基礎(chǔ)知識總結(jié)系列感興趣的同學(xué)可以關(guān)注我的博客(文末給出我的博客地址)。

一、本文梗概

這一篇文章我想寫一下List集合元素去重的8種方法,實(shí)際上通過靈活的運(yùn)用、排列組合不一定是8種,可能有18種方法。

對象元素整體去重的4種方法 按照對象屬性去重的4種方法

為了在下文中進(jìn)行測試內(nèi)容講解,我們先做一些初始化數(shù)據(jù)

public class ListRmDuplicate { private List<String> list; private List<Player> playerList; @BeforeEach public void setup() { list = new ArrayList<>(); list.add('kobe'); list.add('james'); list.add('curry'); list.add('zimug'); list.add('zimug'); playerList= new ArrayList<>(); playerList.add(new Player('kobe','10000')); //科比萬歲 playerList.add(new Player('james','32')); playerList.add(new Player('curry','30')); playerList.add(new Player('zimug','27')); // 注意這里名字重復(fù) playerList.add(new Player('zimug','18')); //注意這里名字和年齡重復(fù) playerList.add(new Player('zimug','18')); //注意這里名字和年齡重復(fù) }}

Player對象就是一個(gè)普通的java對象,有兩個(gè)成員變量name與age,實(shí)現(xiàn)了帶參數(shù)構(gòu)造函數(shù)、toString、equals和hashCode方法、以及GET/SET方法。

二、集合元素整體去重

下文中四種方法對List中的String類型以集合元素對象為單位整體去重。如果你的List放入的是Object對象,需要你去實(shí)現(xiàn)對象的equals和hashCode方法,去重的代碼實(shí)現(xiàn)方法和List<String>去重是一樣的。

第一種方法

是大家最容易想到的,先把List數(shù)據(jù)放入Set,因?yàn)镾et數(shù)據(jù)結(jié)構(gòu)本身具有去重的功能,所以再將SET轉(zhuǎn)為List之后就是去重之后的結(jié)果。這種方法在去重之后會(huì)改變原有的List元素順序,因?yàn)镠ashSet本身是無序的,而TreeSet排序也不是List種元素的原有順序。

@Testvoid testRemove1() { /*Set<String> set = new HashSet<>(list); List<String> newList = new ArrayList<>(set);*/ //去重并排序的方法(如果是字符串,按字母表排序。如果是對象,按Comparable接口實(shí)現(xiàn)排序) //List<String> newList = new ArrayList<>(new TreeSet<>(list)); //簡寫的方法 List<String> newList = new ArrayList<>(new HashSet<>(list)); System.out.println( '去重后的集合: ' + newList);}

控制臺打印結(jié)果如下:

去重后的集合: [kobe, james, zimug, curry]

第二種方法

使用就比較簡單,先用stream方法將集合轉(zhuǎn)換成流,然后distinct去重,最后在將Stream流collect收集為List。

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

控制臺打印結(jié)果如下:

去重后的集合: [kobe, james, curry, zimug]

第三種方法

這種方法利用了set.add(T),如果T元素已經(jīng)存在集合中,就返回false。利用這個(gè)方法進(jìn)行是否重復(fù)的數(shù)據(jù)判斷,如果不重復(fù)就放入一個(gè)新的newList中,這個(gè)newList就是最終的去重結(jié)果

//三個(gè)集合類list、newList、set,能夠保證順序@Testvoid testRemove3() { Set<String> set = new HashSet<>(); List<String> newList = new ArrayList<>(); for (String str :list) { if(set.add(str)){ //重復(fù)的話返回false newList.add(str); } } System.out.println( '去重后的集合: ' + newList);}

控制臺打印結(jié)果和第二種方法一致。

第四種方法

這種方法已經(jīng)脫離了使用Set集合進(jìn)行去重的思維,而是使用newList.contains(T)方法,在向新的List添加數(shù)據(jù)的時(shí)候判斷這個(gè)數(shù)據(jù)是否已經(jīng)存在,如果存在就不添加,從而達(dá)到去重的效果。

//優(yōu)化 List、newList、set,能夠保證順序@Testvoid testRemove4() { List<String> newList = new ArrayList<>(); for (String cd:list) { if(!newList.contains(cd)){ //主動(dòng)判斷是否包含重復(fù)元素 newList.add(cd); } } System.out.println( '去重后的集合: ' + newList);}

控制臺打印結(jié)果和第二種方法一致。

三、按照集合元素對象屬性去重

其實(shí)在實(shí)際的工作中,按照集合元素對象整體去重的應(yīng)用的還比較少,更多的是要求我們按照元素對象的某些屬性進(jìn)行去重。看到這里請大家回頭去看一下上文中,構(gòu)造的初始化數(shù)據(jù)playerList,特別注意其中的一些重復(fù)元素,以及成員變量重復(fù)。

第一種方法

為TreeSet實(shí)現(xiàn)Comparator接口,如果我們希望按照Player的name屬性進(jìn)行去重,就去在Comparator接口中比較name。下文中寫了兩種實(shí)現(xiàn)Comparator接口方法:

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

@Testvoid 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()); });*/ //將去重之后的結(jié)果打印出來 new ArrayList<>(playerSet).forEach(System.out::println);}

輸出結(jié)果如下:三個(gè)zimug因?yàn)閚ame重復(fù),另外兩個(gè)被去重。但是因?yàn)槭褂玫搅薚reeSet,list中元素被重新排序。

Player{name=’curry’, age=’30’}Player{name=’james’, age=’32’}Player{name=’kobe’, age=’10000’}Player{name=’zimug’, age=’27’}

第二種方法

這種方法是網(wǎng)上很多的文章中用來顯示自己很牛的方法,但是在筆者看來有點(diǎn)脫了褲子放屁,多此一舉。既然大家都說有這種方法,我不寫好像我不牛一樣。我為什么說這種方法是“脫了褲子放屁”?

首先用stream()把list集合轉(zhuǎn)換成流 然后用collect及toCollection把流轉(zhuǎn)換成集合 然后剩下的就和第一種方法一樣了

前兩步不是脫了褲子放屁么?看看就得了,實(shí)際應(yīng)用意義不大,但是如果是為了學(xué)習(xí)Stream流的使用方法,搞出這么一個(gè)例子還是有可取之處的。

@Testvoid testRemove6() { List<Player> newList = playerList.stream().collect(Collectors .collectingAndThen( Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(Player::getName))), ArrayList::new)); newList.forEach(System.out::println);}

控制臺打印輸出和第一種方法一樣。

第三種方法

這種方法也是筆者建議大家使用的一種方法,咋一看好像代碼量更大了,但實(shí)際上這種方法是應(yīng)用比較簡單的方法。

Predicate(有人管這個(gè)叫斷言,從英文的角度作為名詞可以翻譯為謂詞,作為動(dòng)詞可以翻譯為斷言)。謂詞就是用來修飾主語的,比如:喜歡唱歌的小鳥,喜歡唱歌就是謂詞,用來限定主語的范圍。所以我們這里是用來filter過濾的,也是用來限制主語范圍的,所以我認(rèn)為翻譯為謂詞更合適。隨便吧,看你怎么覺得怎么理解合理、好記,你就怎么來。

首先我們定義一個(gè)謂詞Predicate用來過濾,過濾的條件是distinctByKey。謂詞返回ture元素保留,返回false元素被過濾掉。 當(dāng)然我們的需求是過濾掉重復(fù)元素。我們?nèi)ブ剡壿嬍峭ㄟ^map的putIfAbsent實(shí)現(xiàn)的。putIfAbsent方法添加鍵值對,如果map集合中沒有該key對應(yīng)的值,則直接添加,并返回null,如果已經(jīng)存在對應(yīng)的值,則依舊為原來的值。 如果putIfAbsent返回null表示添加數(shù)據(jù)成功(不重復(fù)),如果putIfAbsent返回value(value==null :false),則滿足了distinctByKey謂詞的條件元素被過濾掉。

這種方法雖然看上去代碼量增大了,但是distinctByKey謂詞方法只需要被定義一次,就可以無限復(fù)用。

@Testvoid 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對應(yīng)的值,則直接添加,并返回null,如果已經(jīng)存在對應(yīng)的值,則依舊為原來的值。 //如果返回null表示添加數(shù)據(jù)成功(不重復(fù)),不重復(fù)(null==null :TRUE) return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;}

輸出結(jié)果如下:三個(gè)zimug因?yàn)閚ame重復(fù),另外兩個(gè)被去重。并且沒有打亂List的原始順序

Player{name=’kobe’, age=’10000’}Player{name=’james’, age=’32’}Player{name=’curry’, age=’30’}Player{name=’zimug’, age=’27’}

第四種方法

第四種方法實(shí)際上不是新方法,上面的例子都是按某一個(gè)對象屬性進(jìn)行去重,如果我們想按照某幾個(gè)元素進(jìn)行去重,就需要對上面的三種方法進(jìn)行改造。我只改造其中一個(gè),另外幾個(gè)改造的原理是一樣的,就是把多個(gè)比較屬性加起來,作為一個(gè)String屬性進(jìn)行比較。

@Testvoid testRemove8() { Set<Player> playerSet = new TreeSet<>(Comparator.comparing(o -> (o.getName() + '' + o.getAge()))); playerSet.addAll(playerList); new ArrayList<>(playerSet).forEach(System.out::println);}

總結(jié)

到此這篇關(guān)于Java中List集合對象去重及按屬性去重的8種方法的文章就介紹到這了,更多相關(guān)java list集合去重內(nèi)容請搜索好吧啦網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持好吧啦網(wǎng)!

標(biāo)簽: Java
相關(guān)文章:
主站蜘蛛池模板: 青青草免费在线视频 | 国产91视频免费 | 极品美女一级毛片 | a高清免费毛片久久 | 国产精品亚洲午夜不卡 | 一级成人毛片免费观看欧美 | 国产亚洲精品成人久久网站 | 看中国国产一级毛片真人视频 | 亚洲精品国产经典一区二区 | 欧美精品国产制服第一页 | 中国黄色大片 | 香蕉在线观看视频 | 精品久久久久久国产免费了 | 午夜aaaa| 国产精品久久久久久久成人午夜 | 国产伦理久久精品久久久久 | 黄色福利视频 | 日本无吗中文字幕免费婷婷 | 大尺度做爰床戏呻吟免费观看91 | 欧美高清另类 | 精品国产成人a区在线观看 精品国产成人a在线观看 | 免费观看欧美一级特黄 | 国产精品亚洲专区在线观看 | 成人毛片18岁女人毛片免费看 | 免费一级毛片在线播放放视频 | 91精品国产91久久久久青草 | 日韩在线一区二区三区免费视频 | 日本黄色免费网站 | 99视频在线永久免费观看 | 欧美日本高清 | 久久久久嫩草影院精品 | 曰批美女免费视频播放 | 达达兔午夜国产精品 | 免费毛片网站 | 制服丝袜自拍偷拍 | 久久精品综合免费观看 | 欧美丰满丝袜videossex | 娇小性色xxxxx中文 | 日韩一区二区天海翼 | 99久久精品6在线播放 | 99久久综合狠狠综合久久 |