关于大量数据去重的基本算法思路

经常在项目中遇到需要将重复元素去掉的问题比如有以下几个典型的场景


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 uniqueItemKeepFirst(List origin){

//利用set数据的key特性去除重复保留第一个数据,值为1
Set compSet = new HashSet();

//定义返回唯一的去重了数组
List resultList = new ArrayList();

for (String item : origin) {

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

}

return resultList;

}

/**
* 将一个数组中所有重复的元素去掉,保留最后一个
*/
public static List uniqueItemKeepLast(List origin){

//利用set数据的key特性去除重复保留第一个数据,值为1
Set compSet = new HashSet();

//定义返回唯一的去重了数组
List resultList = new ArrayList();

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 uniqueItemKeepFirstUser(List origin){

//利用set数据的key特性去除重复保留第一个数据,值为1
Set compSet = new HashSet();

//定义返回唯一的去重了数组
List resultList = new ArrayList();

for (User item : origin) {

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

}

return resultList;

}


/**
* 将一个数组中所有重复的元素去掉,保留最后一个
*/
public static List uniqueItemKeepLastUser(List origin){

//利用set数据的key特性去除重复保留第一个数据,值为1
Set compSet = new HashSet();

//定义返回唯一的去重了数组
List resultList = new ArrayList();

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 origin = new ArrayList();
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 fList = UniqueItem.uniqueItemKeepFirstUser(origin);
long gendataend1 = System.currentTimeMillis();
System.out.println("100w条数据去重保留第一条的时间是:"+(gendataend1-gendataStart1)+"毫秒");

//剔除重复数据,保留第一条
long gendataStart2 = System.currentTimeMillis();
List 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可以出来完,完全可以秒杀使用各种算法的结果

并且可以看出保留第一条数据和保留最新的数据的结果相差特别明显

你可能感兴趣的:(高效排序)