1. 程式人生 > >關於大量資料去重的基本演算法思路

關於大量資料去重的基本演算法思路

經常在專案中遇到需要將重複元素去掉的問題比如有以下幾個典型的場景

1.對於百萬級或者千萬級資料要求去重保留第一個元素

2.對於百萬級或者千萬級資料要求去重保留第最後一元素

在專案中大家寫了各種演算法,我覺得大家寫的都挺好的,但是其實只要利用好java API中的集合類

這種問題有很高效的解決方式,就是利用集合Set元素不允許重合這一特性直接使用就行

一下我就string 元素,以及物件元素簡單寫了一下,可以表述基本思路,當然實際專案中使用比這複雜得多

1.核心類

package com.gqp;


import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;


public class UniqueItem {

/**
* 將一個數組中所有重複的元素去掉,保留第一個
*/
public static List<String> uniqueItemKeepFirst(List<String> origin){

//利用set資料的key特性去除重複保留第一個資料,值為1
Set<String> compSet = new HashSet<String>();

//定義返回唯一的去重了陣列
List<String> resultList = new ArrayList<String>();

for (String item : origin) {

//新增新元素
if (!compSet.contains(item)) {
compSet.add(item);
resultList.add(item);
}

}

return resultList;

}

/**
* 將一個數組中所有重複的元素去掉,保留最後一個
*/
public static List<String> uniqueItemKeepLast(List<String> origin){

//利用set資料的key特性去除重複保留第一個資料,值為1
Set<String> compSet = new HashSet<String>();

//定義返回唯一的去重了陣列
List<String> resultList = new ArrayList<String>();

for (String item : origin) {

//新增新元素
if (!compSet.contains(item)) {
compSet.add(item);
//最新的總是新增
resultList.add(item);
}else {
//存在替換這個元素
resultList.set(resultList.indexOf(item), item);
}

}

return resultList;

}

/**
* 將一個數組中所有重複的元素去掉,保留第一個
*/
public static List<User> uniqueItemKeepFirstUser(List<User> origin){

//利用set資料的key特性去除重複保留第一個資料,值為1
Set<User> compSet = new HashSet<User>();

//定義返回唯一的去重了陣列
List<User> resultList = new ArrayList<User>();

for (User item : origin) {

//新增新元素
if (!compSet.contains(item)) {
compSet.add(item);
resultList.add(item);
}

}

return resultList;

}


/**
* 將一個數組中所有重複的元素去掉,保留最後一個
*/
public static List<User> uniqueItemKeepLastUser(List<User> origin){

//利用set資料的key特性去除重複保留第一個資料,值為1
Set<User> compSet = new HashSet<User>();

//定義返回唯一的去重了陣列
List<User> resultList = new ArrayList<User>();

for (User item : origin) {

//新增新元素
if (!compSet.contains(item)) {
compSet.add(item);
//最新的總是新增
resultList.add(item);
}else {
//存在則替換這個元素
resultList.set(resultList.indexOf(item), item);
}
}

return resultList;

}

}

2.簡單的一個user類

package com.gqp;


public class User {

private String name;
private Long genLong;

public User(String name,Long genLong){
this.name=name;
this.genLong=genLong;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Long getGenLong() {
return genLong;
}
public void setGenLong(Long genLong) {
this.genLong = genLong;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
final User other = (User) obj;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}

}

3.測試用user,這樣比較耗時

package com.gqp;


import java.util.ArrayList;
import java.util.List;




public class TestMain {


public static void main(String[] args) throws InterruptedException {

//
String[] millios = new String[11];
millios[0]="guo1";
millios[1]="guo2";
millios[2]="guo3";
millios[3]="guo4";
millios[4]="guor";
millios[5]="guo1";
millios[6]="guo4";
millios[7]="guo3";
millios[8]="guo2";
millios[9]="guo1";
millios[10]="nihao";

//產生100W條資料

List<User> origin = new ArrayList<User>();
long gendataStart = System.currentTimeMillis();
for (int i = 0; i < 25000000; i++) {
User u = new User(millios[i%11],System.currentTimeMillis());
origin.add(u);
}
long gendataend = System.currentTimeMillis();
System.out.println("產生100w條資料的時間是:"+(gendataend-gendataStart)+"毫秒");

//遍歷
long gendataStart0 = System.currentTimeMillis();
for (int i = 0; i < origin.size(); i++) {
origin.get(i);
}
long gendataend0 = System.currentTimeMillis();
System.out.println("遍歷100w條資料的時間是:"+(gendataend0-gendataStart0)+"毫秒");

//剔除重複資料,保留第一條
long gendataStart1 = System.currentTimeMillis();
List<User> fList = UniqueItem.uniqueItemKeepFirstUser(origin);
long gendataend1 = System.currentTimeMillis();
System.out.println("100w條資料去重保留第一條的時間是:"+(gendataend1-gendataStart1)+"毫秒");

//剔除重複資料,保留第一條
long gendataStart2 = System.currentTimeMillis();
List<User> LList =UniqueItem.uniqueItemKeepLastUser(origin);
long gendataend2 = System.currentTimeMillis();
System.out.println("100w條資料去重保留最後一條的時間是:"+(gendataend2-gendataStart2)+"毫秒");

//一下是結果的對比
System.out.println(fList.toString());
for (User user : fList) {

System.out.println(user.getName()+"-"+user.getGenLong());//結果一樣,但是可以從資料產生時的時間可以看出保留第一個

}

System.out.println(LList.toString());
for (User user : LList) {
System.out.println(user.getName()+"-"+user.getGenLong());//結果一樣,但是可以從資料產生時的時間可以看出保留最後一個
}
}


}

4.一下是測試的結果

100w時


1000w時


2500w時


總結

可以看出單機下跑資料時,百萬級是秒殺,千萬級也就1s可以出來完,完全可以秒殺使用各種演算法的結果

並且可以看出保留第一條資料和保留最新的資料的結果相差特別明顯