前言
前几天. 工作中用到了List的交集, 并集, 补集. 运算. 之前有封装过相关的List工具类. 在此, 再次总结一下.
List 的交集/并集/补集 运算(原生方法)
- 交集
/**
* 交集.
* 注意直接使用 retainAll方法会改变原数据集合. 需要拷贝使用.
*/
public static <T> List<T> intersection(java.util.List<T> listA, List<T> listB){
if(CollectionUtils.isEmpty(listA)){
return listB;
} else if(CollectionUtils.isEmpty(listB)){
return listA;
}
List<T> copyOfArrayListA = new ArrayList<>(listA);
copyOfArrayListA.retainAll(listB);
return copyOfArrayListA;
}
- 并集
/**
* 并集.
*/
public static <T> List<T> union(java.util.List<T> listA, List<T> listB){
if(CollectionUtils.isEmpty(listA)){
return listB;
} else if(CollectionUtils.isEmpty(listB)){
return listA;
}
List<T> copyOfArrayListA = new ArrayList<>(listA);
copyOfArrayListA.removeAll(listB);
copyOfArrayListA.addAll(listB);
return copyOfArrayListA;
}
- 补集
/**
* 补集.
*/
public static <T> List<T> complement(java.util.List<T> listA, List<T> listB){
if(CollectionUtils.isEmpty(listA)){
return listB;
} else if(CollectionUtils.isEmpty(listB)){
return listA;
}
List<T> intersectionCollection = intersection(listA, listB);
List<T> unionCollection = union(listA, listB);
unionCollection.removeAll(intersectionCollection);
return unionCollection;
}
- 测试
public static <T> void testPrintListData(List<T> dataList){
if(CollectionUtils.isEmpty(dataList)){
return;
}
System.out.println("DataList Print:");
System.out.print("[");
dataList.forEach(data ->{
System.out.print(data.toString()+" ");
});
System.out.print("]");
System.out.println("");
}
public static void main(String[] args) {
List<String> listA = new ArrayList<>();
listA.add("A");
listA.add("C");
listA.add("D");
List<String> listB = new ArrayList<>();
listB.add("A");
listB.add("B");
listB.add("C");
List<String> intersectionList = intersection(listA, listB);
System.out.println("Intersection:");
testPrintListData(intersectionList);
List<String> unionList = union(listA, listB);
System.out.println("Union:");
testPrintListData(unionList);
List<String> complement = complement(listA, listB);
System.out.println("Complement:");
testPrintListData(complement);
}
- 测试结果
Intersection:
DataList Print:
[A C ]
Union:
DataList Print:
[D A B C ]
Complement:
DataList Print:
[D B ]
- 要点1 如何判断2个对象相同?
public boolean retainAll(Collection<?> c) {
Objects.requireNonNull(c);
return batchRemove(c, true);
}
private boolean batchRemove(Collection<?> c, boolean complement) {
final Object[] elementData = this.elementData;
int r = 0, w = 0;
boolean modified = false;
try {
for (; r < size; r++)
if (c.contains(elementData[r]) == complement)
elementData[w++] = elementData[r];
} finally {
// Preserve behavioral compatibility with AbstractCollection,
// even if c.contains() throws.
if (r != size) {
System.arraycopy(elementData, r,
elementData, w,
size - r);
w += size - r;
}
if (w != size) {
// clear to let GC do its work
for (int i = w; i < size; i++)
elementData[i] = null;
modCount += size - w;
size = w;
modified = true;
}
}
return modified;
}
/**
* Returns <tt>true</tt> if this list contains the specified element.
* More formally, returns <tt>true</tt> if and only if this list contains
* at least one element <tt>e</tt> such that
* <tt>(o==null ? e==null : o.equals(e))</tt>.
*
* @param o element whose presence in this list is to be tested
* @return <tt>true</tt> if this list contains the specified element
*/
public boolean contains(Object o) {
return indexOf(o) >= 0;
}
/**
* Returns the index of the first occurrence of the specified element
* in this list, or -1 if this list does not contain the element.
* More formally, returns the lowest index <tt>i</tt> such that
* <tt>(o==null ? get(i)==null : o.equals(get(i)))</tt>,
* or -1 if there is no such index.
*/
public int indexOf(Object o) {
if (o == null) {
for (int i = 0; i < size; i++)
if (elementData[i]==null)
return i;
} else {
for (int i = 0; i < size; i++)
if (o.equals(elementData[i]))
return i;
}
return -1;
}
基于以上方法. 我们可以看出. 此方法主要是使用, equals()
方法来进行实现的.
- 要点2
直接使用retainAll()
等方法. 会直接改变原集合的值. 在使用中需要使用拷贝集合进行操作.
Collections工具包内
TODO.