前言
最近又是一輪代碼review , 發現了一些實現去重的代碼,在使用 lsit.contain ......
如:

我沉思,是不是其實很多初學者也存在這種去重使用問題?
所以我選擇把這個事情整出來,分享一下。
基于 Spring Boot + MyBatis Plus + Vue & Element 實現的后臺管理系統 + 用戶小程序,支持 RBAC 動態權限、多租戶、數據權限、工作流、三方登錄、支付、短信、商城等功能
- 項目地址:https://github.com/YunaiV/ruoyi-vue-pro
- 視頻教程:https://doc.iocoder.cn/video/
正文
首先是造出一個 List
模擬數據,一共2W條,里面有一半數據1W條是重復的:
publicstaticListgetTestList() {
Listlist=newArrayList<>();
for(inti=1;i<=?10000;i++){
list.add(String.valueOf(i));
}
for(inti=10000;i>=1;i--){
list.add(String.valueOf(i));
}
returnlist;
}
先看看 我們用contain 去重的 代碼:
/**
*使用list.contain去重
*
*@paramtestList
*/
privatestaticvoiduseContain2Distinct(ListtestList) {
System.out.println("contains 開始去重,條數:"+testList.size());
ListtestListDistinctResult=newArrayList<>();
for(Stringstr:testList){
if(!testListDistinctResult.contains(str)){
testListDistinctResult.add(str);
}
}
System.out.println("contains 去重完畢,條數:"+testListDistinctResult.size());
}
我們調用一下看看耗時:
publicstaticvoidmain(String[]args){
ListtestList=getTestList();
StopWatchstopWatch=newStopWatch();
stopWatch.start();
useContainDistinct(testList);
stopWatch.stop();
System.out.println("去重最終耗時"+stopWatch.getTotalTimeMillis());
}
耗時:

評價:list.contain 的效率,我的建議是,知道就行,別用。
眾所周知Set 不存在 重復數據, 所以我們來看看 使用HashSet去重的性能:
ps:這里是采取使用 set的add 方法做去重
/**
*使用set去重
*
*@paramtestList
*/
privatestaticvoiduseSetDistinct(ListtestList) {
System.out.println("HashSet.add 開始去重,條數:"+testList.size());
ListtestListDistinctResult=newArrayList<>(newHashSet(testList));
System.out.println("HashSet.add 去重完畢,條數:"+testListDistinctResult.size());
}
我們調用一下看看耗時:
publicstaticvoidmain(String[]args){
ListtestList=getTestList();
StopWatchstopWatch=newStopWatch();
stopWatch.start();
useSetDistinct(testList);
stopWatch.stop();
System.out.println("去重最終耗時"+stopWatch.getTotalTimeMillis());
}
耗時:

評價:HashSet 的效率,我的建議是,推薦。
為什么耗時 差距這么大?
不多說,我們看源碼:
list.contains(o)
:

可以看到里面用到了 index(o)
:

時間復雜度 :O(n)
,n: 元素個數
那么我們看看 set.add(o)
是怎么樣的 :

map的add , 老生常談就不談了,hash完 直接塞到某個位置, 時間復雜度 : O(1)
。
所以 O(n)
和 O(1)
誰快 誰慢 ?顯然。
ps:順嘴說下 hashset的 contain

時間復雜度也是 :O(1)

那么我們最后再看看別的去重:
雙for循環 ,remove去重
/**
*使用雙for循環去重
*@paramtestList
*/
privatestaticvoiduse2ForDistinct(ListtestList) {
System.out.println("list 雙循環開始去重,條數:"+testList.size());
for(inti=0;ifor(intj=i+1;jif(testList.get(i).equals(testList.get(j))){
testList.remove(j);
}
}
}
System.out.println("list 雙循環去重完畢,條數:"+testList.size());
}
publicstaticvoidmain(String[]args){
ListtestList=getTestList();
StopWatchstopWatch=newStopWatch();
stopWatch.start();
use2ForDistinct(testList);
stopWatch.stop();
System.out.println("去重最終耗時"+stopWatch.getTotalTimeMillis());
}
耗時:

評價:知道就行,圖個樂,別用,賊慢,而且代碼看起來亂:。
stream的distinct去重:
/**
*使用Stream去重
*
*@paramtestList
*/
privatestaticvoiduseStreamDistinct(ListtestList) {
System.out.println("stream 開始去重,條數:"+testList.size());
ListtestListDistinctResult=testList.stream().distinct().collect(Collectors.toList());
System.out.println("stream 去重完畢,條數:"+testListDistinctResult.size());
}
publicstaticvoidmain(String[]args){
ListtestList=getTestList();
StopWatchstopWatch=newStopWatch();
stopWatch.start();
useStreamDistinct(testList);
stopWatch.stop();
System.out.println("去重最終耗時"+stopWatch.getTotalTimeMillis());
}
耗時:

評價:還不錯,主要是代碼也蠻簡潔,有一點點動心。
好了,該篇就到這。
-
數據
+關注
關注
8文章
7233瀏覽量
90784 -
代碼
+關注
關注
30文章
4882瀏覽量
70046 -
spring
+關注
關注
0文章
340瀏覽量
14807
原文標題:不好意思,list.contain 去重該換換了!
文章出處:【微信號:芋道源碼,微信公眾號:芋道源碼】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
評論