说明:第一篇我们使用HashSet,也即是HasMap的数据结构实现的去重,这里面有几个问题:
- 性能问题,在去重的过程中创建了不必要的过渡对象,实际的效率会有所降低;
- 对实体类有侵入,为了覆盖hashcode和equals方法,我们写了抽象类来实现这部分代码并设置去重属性,那么所要去重的实体类必须继承自这个抽象类;
- 无法实现两个对象在我的定义下等价时的取舍,也就是去重的对象我们没办法控制;
- List原有的顺序被打乱了。
思路:如果能够在对原有集合进行遍历的过程中,遇到相同的对象,根据我们给定的规则取舍,应该会是一个相对较好的解决方式。
实现:
1.写一个接口,用来给定当我们遇到两个对象时,应该抛弃哪一个;返回null时不移除
public interface ReduceComparable<T> {
//返回值是我们抛弃的对象,有可能是t1,也可能是t2,根据需求自行实现
T compare(T t1, T t2);
}
2.写一个类,用来执行List的去重逻辑;对传入的list进行反向两层遍历,一旦遇到相同的,则从list中删除1中规则返回的对象,并从内层循环中跳出,接着执行下一次外层循环,这一次外层循环的size一定要是list当前的size;遍历结束之后,所有重复的对象都会按照我们的规则移除,并且在这个过程中没有任何新的中间对象产生;经过对比,这种方法的效率大约是采用Set去重方法的20倍以上;
public class ListReducer<T> {
private ReduceComparable<T> reduce;
public ListReducer(ReduceComparable<T> reduce) {
this.reduce = reduce;
}
private void checkReduce() {
if (reduce == null)
throw new RuntimeException("ListReducer need a ReduceComparable to do reduce!");
}
public void reduce(List<? extends T> list) {
checkReduce();
for (int i = list.size() - 1; i >= 0; i--) {
for (int j = i - 1; j >= 0; j--) {
T vehicle1 = list.get(i);
T vehicle2 = list.get(j);
T obj = reduce.compare(vehicle1, vehicle2);
if (obj != null) {
list.remove(obj);
break;
}
}
}
}
}
3.实体类,此时的实体类无需进行任何修改;
public class Vehicle {
private String plateNumber;
private String model;
private String color;
private int size;
public int getSize() {
return size;
}
public void setSize(int size) {
this.size = size;
}
public String getPlateNumber() {
return plateNumber;
}
public void setPlateNumber(String plateNumber) {
this.plateNumber = plateNumber;
}
public String getModel() {
return model;
}
public void setModel(String model) {
this.model = model;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
@Override
public String toString() {
return "Vehicle [plateNumber=" + plateNumber + ", model=" + model + ", color=" + color + ", size=" + size + "]";
}
}
4.可以根据自己需求实现ReduceComparable接口,这里简单实现一个;如果两个vehicle的color一样,那么谁的size大抛弃哪一个,即保留size小的;
public class VehicleReduce implements ReduceComparable<Vehicle>{
@Override
public Vehicle compare(Vehicle vehicle1, Vehicle vehicle2) {
if(vehicle1.getPlateNumber().equals(vehicle2.getPlateNumber())) {
if(vehicle1.getModel().equals(vehicle2.getModel())) {
if (vehicle1.getColor().equals(vehicle2.getColor())) {
if (vehicle1.getSize() > vehicle2.getSize()) {
return vehicle1;
} else {
return vehicle2;
}
}
}
}
return null;
}
}
5.简单调用一下;
public static void main(String[] args) {
String originJson = "[{\"plateNumber\":\"京A00001\",\"model\":\"tesla90\",\"color\":\"black\",\"size\":12},"
+ "{\"plateNumber\":\"京A00002\",\"model\":\"tesla90\",\"color\":\"black\",\"size\":11},"
+ "{\"plateNumber\":\"京A00001\",\"model\":\"tesla90\",\"color\":\"black\",\"size\":17}]";
List<Vehicle> list = JSONArray.parseArray(originJson, Vehicle.class);
System.out.println("before: " + list);
ListReducer<Vehicle> listReducer = new ListReducer<>(new VehicleReduce());
listReducer.reduce(list);
System.out.println("after: " + list);
}
按照4中的实现,应该会在前三个字段都一致时,保留size小的;程序的执行结果如下:
before: [Vehicle [plateNumber=京A00001, model=tesla90, color=black, size=12], Vehicle [plateNumber=京A00002, model=tesla90, color=black, size=11], Vehicle [plateNumber=京A00001, model=tesla90, color=black, size=13]]
after: [Vehicle [plateNumber=京A00001, model=tesla90, color=black, size=12], Vehicle [plateNumber=京A00002, model=tesla90, color=black, size=11]]