激情久久久_欧美视频区_成人av免费_不卡视频一二三区_欧美精品在欧美一区二区少妇_欧美一区二区三区的

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - Java教程 - Java中對List去重 Stream去重的解決方法

Java中對List去重 Stream去重的解決方法

2021-04-21 14:51Ryan.Miao Java教程

這篇文章主要介紹了Java中對List去重, Stream去重的問題解答,文中給大家介紹了Java中List集合去除重復數據的方法,需要的朋友可以參考下

問題

當下互聯網技術成熟,越來越多的趨向去中心化、分布式、流計算,使得很多以前在數據庫側做的事情放到了java端。今天有人問道,如果數據庫字段沒有索引,那么應該如何根據該字段去重?大家都一致認為用java來做,但怎么做呢?

解答

忽然想起以前寫過list去重的文章,找出來一看。做法就是將list中對象的hashcode和equals方法重寫,然后丟到hashset里,然后取出來。這是最初剛學java的時候像被字典一樣背寫出來的答案。就比如面試,面過號稱做了3年java的人,問set和hashmap的區別可以背出來,問如何實現就不知道了。也就是說,初學者只背特性。但真正在項目中使用的時候你需要確保一下是不是真的這樣。因為背書沒用,只能相信結果。你需要知道hashset如何幫我做到去重了。換個思路,不用hashset可以去重嗎?最簡單,最直接的辦法不就是每次都拿著和歷史數據比較,都不相同則插入隊尾。而hashset只是加速了這個過程而已。

首先,給出我們要排序的對象user

?
1
2
3
4
5
6
7
8
9
10
11
12
@data
@builder
@allargsconstructor
public class user {
 private integer id;
 private string name;
}
list<user> users = lists.newarraylist(
    new user(1, "a"),
    new user(1, "b"),
    new user(2, "b"),
    new user(1, "a"));

目標是取出id不重復的user,為了防止扯皮,給個規則,只要任意取出id唯一的數據即可,不用拘泥id相同時算哪個。

用最直觀的辦法

這個辦法就是用一個空list存放遍歷后的數據。

?
1
2
3
4
5
6
7
8
9
10
11
@test
public void dis1() {
  list<user> result = new linkedlist<>();
  for (user user : users) {
   boolean b = result.stream().anymatch(u -> u.getid().equals(user.getid()));
   if (!b) {
    result.add(user);
   }
  }
  system.out.println(result);
}

用hashset

背過特性的都知道hashset可以去重,那么是如何去重的呢? 再深入一點的背過根據hashcode和equals方法。那么如何根據這兩個做到的呢?沒有看過源碼的人是無法繼續的,面試也就到此結束了。

事實上,hashset是由hashmap來實現的(沒有看過源碼的時候曾經一直直觀的以為hashmap的key是hashset來實現的,恰恰相反)。這里不展開敘述,只要看hashset的構造方法和add方法就能理解了。

?
1
2
3
4
5
6
7
8
9
public hashset() {
  map = new hashmap<>();
}
/**
* 顯然,存在則返回false,不存在的返回true
*/
public boolean add(e e) {
  return map.put(e, present)==null;
}

那么,由此也可以看出hashset的去重復就是根據hashmap實現的,而hashmap的實現又完全依賴于hashcode和equals方法。這下就徹底打通了,想用hashset就必須看好自己的這兩個方法。

在本題目中,要根據id去重,那么,我們的比較依據就是id了。修改如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@override
public boolean equals(object o) {
  if (this == o) {
   return true;
  }
  if (o == null || getclass() != o.getclass()) {
   return false;
  }
  user user = (user) o;
  return objects.equals(id, user.id);
}
@override
public int hashcode() {
  return objects.hash(id);
}
//hashcode
result = 31 * result + (element == null ? 0 : element.hashcode());

其中, objects調用arrays的hashcode,內容如上述所示。乘以31等于x<<5-x。

最終實現如下:

?
1
2
3
4
5
@test
public void dis2() {
  set<user> result = new hashset<>(users);
  system.out.println(result);
}

使用java的stream去重

回到最初的問題,之所以提這個問題是因為想要將數據庫側去重拿到java端,那么數據量可能比較大,比如10w條。對于大數據,采用stream相關函數是最簡單的了。正好stream也提供了distinct函數。那么應該怎么用呢?

?
1
users.parallelstream().distinct().foreach(system.out::println);

沒看到用lambda當作參數,也就是沒有提供自定義條件。幸好javadoc標注了去重標準:

?
1
2
returns a stream consisting of the distinct elements
(according to {@link object#equals(object)}) of this stream.

我們知道,也必須背過這樣一個準則:equals返回true的時候,hashcode的返回值必須相同. 這個在背的時候略微有些邏輯混亂,但只要了解了hashmap的實現方式就不會覺得拗口了。hashmap先根據hashcode方法定位,再比較equals方法。

所以,要使用distinct來實現去重,必須重寫hashcode和equals方法,除非你使用默認的。

那么,究竟為啥要這么做?點進去看一眼實現。

?
1
2
3
4
5
6
7
<p_in> node<t> reduce(pipelinehelper<t> helper, spliterator<p_in> spliterator) {
  // if the stream is sorted then it should also be ordered so the following will also
  // preserve the sort order
  terminalop<t, linkedhashset<t>> reduceop
      = reduceops.<t, linkedhashset<t>>makeref(linkedhashset::new, linkedhashset::add,                           linkedhashset::addall);
  return nodes.node(reduceop.evaluateparallel(helper, spliterator));
}

內部是用reduce實現的啊,想到reduce,瞬間想到一種自己實現distinctbykey的方法。我只要用reduce,計算部分就是把stream的元素拿出來和我自己內置的一個hashmap比較,有則跳過,沒有則放進去。其實,思路還是最開始的那個最直白的方法。

?
1
2
3
4
5
6
7
8
9
@test
public void dis3() {
  users.parallelstream().filter(distinctbykey(user::getid))
    .foreach(system.out::println);
}
public static <t> predicate<t> distinctbykey(function<? super t, ?> keyextractor) {
  set<object> seen = concurrenthashmap.newkeyset();
  return t -> seen.add(keyextractor.apply(t));
}

當然,如果是并行stream,則取出來的不一定是第一個,而是隨機的。

上述方法是至今發現最好的,無侵入性的。但如果非要用distinct。只能像hashset那個方法一樣重寫hashcode和equals。

小結

會不會用這些東西,你只能去自己練習過,不然到了真正要用的時候很難一下子就拿出來,不然就冒險用。而若真的想大膽使用,了解規則和實現原理也是必須的。比如,linkedhashset和hashset的實現有何不同。

附上賊簡單的linkedhashset源碼:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class linkedhashset<e>
  extends hashset<e>
  implements set<e>, cloneable, java.io.serializable {
  private static final long serialversionuid = -2851667679971038690l;
  public linkedhashset(int initialcapacity, float loadfactor) {
    super(initialcapacity, loadfactor, true);
  }
  public linkedhashset(int initialcapacity) {
    super(initialcapacity, .75f, true);
  }
  public linkedhashset() {
    super(16, .75f, true);
  }
  public linkedhashset(collection<? extends e> c) {
    super(math.max(2*c.size(), 11), .75f, true);
    addall(c);
  }
  @override
  public spliterator<e> spliterator() {
    return spliterators.spliterator(this, spliterator.distinct | spliterator.ordered);
  }
}

Java中對List去重 Stream去重的解決方法

Java中對List去重 Stream去重的解決方法

補充:

java中list集合去除重復數據的方法

1. 循環list中的所有元素然后刪除重復

?
1
2
3
4
5
6
7
8
9
10
public  static  list removeduplicate(list list) {   
 for ( int i =  0 ; i < list.size() -  1 ; i ++ ) {   
   for ( int j = list.size() -  1 ; j > i; j -- ) {   
      if (list.get(j).equals(list.get(i))) {   
       list.remove(j);   
      }   
    }   
   }   
  return list;   
}

2. 通過hashset踢除重復元素

?
1
2
3
4
5
6
public static list removeduplicate(list list) { 
hashset h = new hashset(list); 
list.clear(); 
list.addall(h); 
return list; 
}

3. 刪除arraylist中重復元素,保持順序

?
1
2
3
4
5
6
7
8
9
10
11
12
13
// 刪除arraylist中重復元素,保持順序  
 public static void removeduplicatewithorder(list list) { 
  set set = new hashset(); 
   list newlist = new arraylist(); 
  for (iterator iter = list.iterator(); iter.hasnext();) { 
     object element = iter.next(); 
     if (set.add(element)) 
      newlist.add(element); 
   }  
   list.clear(); 
   list.addall(newlist); 
  system.out.println( " remove duplicate " + list); 
 }

4.把list里的對象遍歷一遍,用list.contain(),如果不存在就放入到另外一個list集合中

?
1
2
3
4
5
6
7
8
9
public static list removeduplicate(list list){
    list listtemp = new arraylist();
    for(int i=0;i<list.size();i++){
      if(!listtemp.contains(list.get(i))){
        listtemp.add(list.get(i));
      }
    }
    return listtemp;
  }

原文鏈接:https://www.cnblogs.com/woshimrf/p/java-list-distinct.html

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 暴力强行进如hdxxx | 久久久综合视频 | 欧美激情综合网 | 被啪羞羞视频在线观看 | 麻豆视频在线免费观看 | 中国一级毛片在线视频 | 亚洲一区二区三区精品在线观看 | 91快色| 黄色的视频免费看 | 久久这里只有精品1 | 国产精品久久久久久久久久久天堂 | 午夜影视一区二区 | 国产成人自拍av | 一级毛片a级 | 牛牛a级毛片在线播放 | 国产一国产一级毛片视频在线 | 女人叉开腿让男人桶 | 91懂色 | 中国hdxxxx护士爽在线观看 | 国产日韩免费观看 | 中国漂亮护士一级a毛片 | 久久吊 | 噜噜噜在线 | 少妇色诱麻豆色哟哟 | 国产69精品久久久久9999不卡免费 | 国产亚洲精品久久久久久久久久 | 免费亚洲视频在线观看 | 精品国产91一区二区三区 | 亚洲精品在线观看免费 | www.成人免费视频 | 美国人成人在线视频 | 久久福利电影网 | 香蕉在线看 | 成人做爽爽爽爽免费国产软件 | 中文字幕一区二区三区四区 | 欧美日本一 | 毛片视 | 91成人免费版 | 久久17| 人成免费a级毛片 | 黄色片网站免费看 |