成人午夜视频全免费观看高清-秋霞福利视频一区二区三区-国产精品久久久久电影小说-亚洲不卡区三一区三区一区

javaList集合對(duì)象去重及按屬性去重的方法有哪些

本篇內(nèi)容介紹了“java List集合對(duì)象去重及按屬性去重的方法有哪些”的有關(guān)知識(shí),在實(shí)際案例的操作過(guò)程中,不少人都會(huì)遇到這樣的困境,接下來(lái)就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!

目前創(chuàng)新互聯(lián)已為上1000家的企業(yè)提供了網(wǎng)站建設(shè)、域名、網(wǎng)絡(luò)空間、網(wǎng)站托管、服務(wù)器租用、企業(yè)網(wǎng)站設(shè)計(jì)、蘭坪網(wǎng)站維護(hù)等服務(wù),公司將堅(jiān)持客戶導(dǎo)向、應(yīng)用為本的策略,正道將秉承"和諧、參與、激情"的文化,與客戶和合作伙伴齊心協(xié)力一起成長(zhǎng),共同發(fā)展。

一、本文梗概

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

  • 對(duì)象元素整體去重的4種方法

  • 按照對(duì)象屬性去重的4種方法

為了在下文中進(jìn)行測(cè)試內(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"));  //科比萬(wàn)歲
    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對(duì)象就是一個(gè)普通的java對(duì)象,有兩個(gè)成員變量name與age,實(shí)現(xiàn)了帶參數(shù)構(gòu)造函數(shù)、toString、equals和hashCode方法、以及GET/SET方法。

二、集合元素整體去重

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

第一種方法

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

[@Test](https://my.oschina.net/azibug)
void testRemove1()  {
  /*Set<String> set = new HashSet<>(list);
  List<String> newList = new ArrayList<>(set);*/

  //去重并排序的方法(如果是字符串,按字母表排序。如果是對(duì)象,按Comparable接口實(shí)現(xiàn)排序)
  //List<String> newList = new ArrayList<>(new TreeSet<>(list));

  //簡(jiǎn)寫的方法
  List<String> newList = new ArrayList<>(new HashSet<>(list));

  System.out.println( "去重后的集合: " + newList);
}

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

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

第二種方法

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

[@Test](https://my.oschina.net/azibug)
void testRemove2()  {
  List<String> newList = list.stream().distinct().collect(Collectors.toList());

  System.out.println( "去重后的集合: " + newList);
}

控制臺(tái)打印結(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,能夠保證順序
[@Test](https://my.oschina.net/azibug)
void 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);

}

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

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

//優(yōu)化 List、newList、set,能夠保證順序
[@Test](https://my.oschina.net/azibug)
void testRemove4() {

  List<String> newList = new  ArrayList<>();
  for (String cd:list) {
    if(!newList.contains(cd)){  //主動(dòng)判斷是否包含重復(fù)元素
      newList.add(cd);
    }
  }
  System.out.println( "去重后的集合: " + newList);

}

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

三、按照集合元素對(duì)象屬性去重

其實(shí)在實(shí)際的工作中,按照集合元素對(duì)象整體去重的應(yīng)用的還比較少,更多的是要求我們按照元素對(duì)象的某些屬性進(jìn)行去重。 看到這里請(qǐng)大家回頭去看一下上文中,構(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)

@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());
  });*/
  //將去重之后的結(jié)果打印出來(lái)
  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)上很多的文章中用來(lái)顯示自己很牛的方法,但是在筆者看來(lái)有點(diǎn)脫了褲子放屁,多此一舉。既然大家都說(shuō)有這種方法,我不寫好像我不牛一樣。我為什么說(shuō)這種方法是“脫了褲子放屁”?

  • 首先用stream()把list集合轉(zhuǎn)換成流

  • 然后用collect及toCollection把流轉(zhuǎn)換成集合

  • 然后剩下的就和第一種方法一樣了

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

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

控制臺(tái)打印輸出和第一種方法一樣。

第三種方法

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

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

  • 首先我們定義一個(gè)謂詞Predicate用來(lái)過(guò)濾,過(guò)濾的條件是distinctByKey。謂詞返回ture元素保留,返回false元素被過(guò)濾掉。

  • 當(dāng)然我們的需求是過(guò)濾掉重復(fù)元素。我們?nèi)ブ剡壿嬍峭ㄟ^(guò)map的putIfAbsent實(shí)現(xiàn)的。putIfAbsent方法添加鍵值對(duì),如果map集合中沒(méi)有該key對(duì)應(yīng)的值,則直接添加,并返回null,如果已經(jīng)存在對(duì)應(yīng)的值,則依舊為原來(lái)的值。

  • 如果putIfAbsent返回null表示添加數(shù)據(jù)成功(不重復(fù)),如果putIfAbsent返回value(value==null :false),則滿足了distinctByKey謂詞的條件元素被過(guò)濾掉。

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

@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方法添加鍵值對(duì),如果map集合中沒(méi)有該key對(duì)應(yīng)的值,則直接添加,并返回null,如果已經(jīng)存在對(duì)應(yīng)的值,則依舊為原來(lái)的值。
  //如果返回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è)被去重。并且沒(méi)有打亂List的原始順序

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

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

@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 List集合對(duì)象去重及按屬性去重的方法有哪些”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識(shí)可以關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實(shí)用文章!

當(dāng)前標(biāo)題:javaList集合對(duì)象去重及按屬性去重的方法有哪些
分享鏈接:http://jinyejixie.com/article28/gpgicp.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站設(shè)計(jì)公司、關(guān)鍵詞優(yōu)化網(wǎng)站維護(hù)、商城網(wǎng)站做網(wǎng)站、網(wǎng)站建設(shè)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

商城網(wǎng)站建設(shè)
三明市| 岳阳县| 岑巩县| 应用必备| 台北市| 页游| 吉林省| 乌拉特中旗| 伊通| 巴中市| 叶城县| 贵南县| 河东区| 防城港市| 镇远县| 姜堰市| 汉阴县| 保山市| 穆棱市| 镇雄县| 丰宁| 隆回县| 石河子市| 永川市| 安龙县| 古浪县| 民丰县| 侯马市| 海宁市| 鹿泉市| 视频| 九江县| 融水| 奉新县| 民权县| 吉首市| 达日县| 丰顺县| 莎车县| 囊谦县| 榆中县|