This commit is contained in:
Looly 2022-08-20 00:38:00 +08:00
parent d17eb88635
commit b5dc741079
4 changed files with 153 additions and 144 deletions

View File

@ -364,28 +364,13 @@ public class CollUtil {
* 结果[a, b, c]此结果中只保留了一个c
*
* @param <T> 集合元素类型
* @param coll1 集合1
* @param coll2 集合2
* @param otherColls 其它集合
* @param colls 集合列表
* @return 交集的集合返回 {@link LinkedHashSet}
* @since 5.3.9
*/
@SafeVarargs
public static <T> Set<T> intersectionDistinct(final Collection<T> coll1, final Collection<T> coll2, final Collection<T>... otherColls) {
// 任意容器为空, 则返回空集
if (isEmpty(coll1) || isEmpty(coll2) || ArrayUtil.hasEmpty((Object[]) otherColls)) {
return new LinkedHashSet<>();
}
final Set<T> result = new LinkedHashSet<>(coll1);
result.retainAll(coll2);
if (ArrayUtil.isNotEmpty(otherColls)) {
for (final Collection<T> otherColl : otherColls) {
result.retainAll(otherColl);
}
}
return result;
public static <T> Set<T> intersectionDistinct(final Collection<T>... colls) {
return CollectionOperation.of(colls).intersectionDistinct();
}
/**
@ -407,30 +392,7 @@ public class CollUtil {
* @return 差集的集合返回 {@link ArrayList}
*/
public static <T> Collection<T> disjunction(final Collection<T> coll1, final Collection<T> coll2) {
if (isEmpty(coll1) || isEmpty(coll2)) {
if (isEmpty(coll1) && isEmpty(coll2)) {
return ListUtil.zero();
} else if (isEmpty(coll1)) {
return coll2;
} else if (isEmpty(coll2)) {
return coll1;
}
}
final List<T> result = new ArrayList<>();
final Map<T, Integer> map1 = countMap(coll1);
final Map<T, Integer> map2 = countMap(coll2);
// 两个集合的全部元素
final Set<T> elements = SetUtil.of(map1.keySet());
elements.addAll(map2.keySet());
// 元素的个数为 该元素在两个集合中的个数的差
for (final T t : elements) {
final int amount = Math.abs(map1.getOrDefault(t, 0) - map2.getOrDefault(t, 0));
for (int i = 0; i < amount; i++) {
result.add(t);
}
}
return result;
return CollectionOperation.of(coll1, coll2).disjunction();
}
/**
@ -469,23 +431,7 @@ public class CollUtil {
* @since 5.3.5
*/
public static <T> List<T> subtractToList(final Collection<T> coll1, final Collection<T> coll2) {
if (isEmpty(coll1)) {
return ListUtil.empty();
}
if (isEmpty(coll2)) {
return ListUtil.of(true, coll1);
}
//将被交数用链表储存防止因为频繁扩容影响性能
final List<T> result = new LinkedList<>();
final Set<T> set = new HashSet<>(coll2);
for (final T t : coll1) {
if (false == set.contains(t)) {
result.add(t);
}
}
return result;
return CollectionOperation.of(coll1, coll2).subtract();
}
/**
@ -588,39 +534,10 @@ public class CollUtil {
return false;
}
// 针对Set的优化
if (coll1 instanceof Set) {
//noinspection SuspiciousMethodCalls
return coll1.containsAll(coll2);
}
final Iterator<?> iterator = coll1.iterator();
// 保存 集合1 已经遍历过的元素
final Set<Object> elementsAlreadySeen = new HashSet<>();
for (final Object curElement : coll2) {
// 集合2的当前元素 已经在集合1中
if (elementsAlreadySeen.contains(curElement)) {
continue;
}
// 集合2的当前元素 是否在集合1中
boolean foundCurrentElement = false;
while (iterator.hasNext()) {
final Object next = iterator.next();
elementsAlreadySeen.add(next);
if (Objects.equals(curElement, next)) {
foundCurrentElement = true;
break;
}
}
// 集合2的当前元素 不在集合1中, 显然不是子集
if (!foundCurrentElement) {
return false;
}
}
return true;
}
/**
* 根据集合返回一个元素计数的 {@link Map}<br>
* 所谓元素计数就是假如这个集合中某个元素出现了n次那将这个元素做为keyn做为value<br>
@ -1771,11 +1688,14 @@ public class CollUtil {
* @since 4.0.6
*/
public static <T> T get(final Collection<T> collection, int index) {
if (isEmpty(collection)) {
if (null == collection) {
return null;
}
final int size = collection.size();
if (0 == size) {
return null;
}
if (index < 0) {
index += size;
}
@ -2193,10 +2113,10 @@ public class CollUtil {
if (isEmpty(mapCollection)) {
return ListUtil.zero();
}
// 统计每个map的values的大小总和
// 统计每个map的大小总和
int size = 0;
for (final Map<?, V> map : mapCollection) {
size += size(map.values());
size += map.size();
}
if (size == 0) {
return ListUtil.zero();
@ -2448,41 +2368,6 @@ public class CollUtil {
return IterUtil.isEqualList(list1, list2);
}
/**
* 判断两个集合是否包含相同的元素(包括个数)
*
* @param coll1 集合1
* @param coll2 集合2
* @return 两个集合是否相同
* @since 6.0.0
*/
public static boolean isEquals(final Collection<?> coll1, final Collection<?> coll2) {
if (coll1 == coll2) {
return true;
}
if (coll1 == null || coll2 == null || coll1.size() != coll2.size()) {
return false;
}
// 针对 Set 的优化
if (coll1 instanceof Set || coll2 instanceof Set) {
//noinspection SuspiciousMethodCalls
return coll1 instanceof Set ? coll1.containsAll(coll2) : coll2.containsAll(coll1);
}
// 给集合1的每个元素计数
//noinspection unchecked
final Map<Object, Integer> countMap1 = countMap((Iterable<Object>) coll1);
for (final Object e : coll2) {
// 该元素若存在, 则个数减去1, 若不存在则个数为-1
final Integer amount = countMap1.merge(e, -1, Integer::sum);
if (amount < 0) {
return false;
}
}
return true;
}
/**
* 一个对象不为空且不存在于该集合中时加入到该集合中<br>
* <pre>

View File

@ -11,7 +11,14 @@ import java.util.Map;
import java.util.Set;
/**
* 集合运算
* 集合运算包括
* <ul>
* <li>求集合的并集</li>
* <li>求集合的唯一并集</li>
* <li>求集合的完全并集</li>
* <li>求集合的交集</li>
* <li>求集合的差集</li>
* </ul>
*
* @param <E> 集合元素类型
*/
@ -137,6 +144,82 @@ public class CollectionOperation<E> {
return result;
}
/**
* 多个集合的唯一交集<br>
* 针对一个集合中存在多个相同元素的情况只保留一个<br>
* 例如集合1[a, b, c, c, c]集合2[a, b, c, c]<br>
* 结果[a, b, c]此结果中只保留了一个c
*
* @return 唯一交集的集合返回 {@link LinkedHashSet}
*/
public Set<E> intersectionDistinct() {
final Collection<E>[] colls = this.colls;
// 任意容器为空, 则返回空集
if (ArrayUtil.isEmpty(colls)) {
return SetUtil.zeroLinked();
}
final Set<E> result = SetUtil.of(true, colls[0]);
for (int i = 1; i < colls.length; i++) {
if(CollUtil.isNotEmpty(colls[i])){
result.retainAll(colls[i]);
}
}
return result;
}
/**
* 多个集合的差集<br>
* 针对一个集合中存在多个相同元素的情况计算每两个集合中此元素的个数保留两个集合中此元素个数差的个数<br>
* 例如
*
* <pre>
* disjunction([a, b, c, c, c], [a, b, c, c]) - [c]
* disjunction([a, b], []) - [a, b]
* disjunction([a, b, c], [b, c, d]) - [a, d]
* </pre>
* 任意一个集合为空返回另一个集合<br>
* 两个集合无差集则返回空集合
*
* @return 差集的集合返回 {@link ArrayList}
*/
public Collection<E> disjunction() {
final Collection<E>[] colls = this.colls;
if (ArrayUtil.isEmpty(colls)) {
return ListUtil.zero();
}
Collection<E> result = colls[0];
for (int i = 1; i < colls.length; i++) {
result = _disjunction(result, colls[i]);
}
return result;
}
/**
* 计算集合的单差集即只返回集合1中有但是集合2集合3...中没有的元素例如
*
* <pre>
* subtract([1,2,3,4],[2,3,4,5]) - [1]
* </pre>
*
* @return 单差集的List
*/
public List<E> subtract() {
final Collection<E>[] colls = this.colls;
if(ArrayUtil.isEmpty(colls)){
return ListUtil.zero();
}
final List<E> result = ListUtil.of(colls[0]);
for (int i = 1; i < colls.length; i++) {
result.removeAll(colls[i]);
}
return result;
}
// region private methods
/**
* 两个集合的并集<br>
* 针对一个集合中存在多个相同元素的情况计算两个集合中此元素的个数保留最多的个数<br>
@ -206,4 +289,49 @@ public class CollectionOperation<E> {
}
return list;
}
/**
* 两个集合的差集<br>
* 针对一个集合中存在多个相同元素的情况计算两个集合中此元素的个数保留两个集合中此元素个数差的个数<br>
* 例如
*
* <pre>
* disjunction([a, b, c, c, c], [a, b, c, c]) - [c]
* disjunction([a, b], []) - [a, b]
* disjunction([a, b, c], [b, c, d]) - [a, d]
* </pre>
* 任意一个集合为空返回另一个集合<br>
* 两个集合无差集则返回空集合
*
* @param <T> 集合元素类型
* @param coll1 集合1
* @param coll2 集合2
* @return 差集的集合返回 {@link ArrayList}
*/
private static <T> Collection<T> _disjunction(final Collection<T> coll1, final Collection<T> coll2) {
if(CollUtil.isEmpty(coll1)){
if(CollUtil.isEmpty(coll2)){
return ListUtil.zero();
}
return coll2;
} else if(CollUtil.isEmpty(coll2)){
return coll1;
}
final List<T> result = new ArrayList<>(coll1.size() + coll2.size());
final Map<T, Integer> map1 = CollUtil.countMap(coll1);
final Map<T, Integer> map2 = CollUtil.countMap(coll2);
// 两个集合的全部元素
final Set<T> elements = SetUtil.of(map1.keySet());
elements.addAll(map2.keySet());
// 元素的个数为 该元素在两个集合中的个数的差
for (final T t : elements) {
final int amount = Math.abs(map1.getOrDefault(t, 0) - map2.getOrDefault(t, 0));
for (int i = 0; i < amount; i++) {
result.add(t);
}
}
return result;
}
// endregion
}

View File

@ -186,6 +186,17 @@ public class SetUtil {
return new HashSet<>(0, 1);
}
/**
* 获取一个初始大小为0的LinkedHashSet这个空Set可变
*
* @param <T> 元素类型
* @return 空的List
* @since 6.0.0
*/
public static <T> Set<T> zeroLinked() {
return new LinkedHashSet<>(0, 1);
}
/**
* 转为只读Set
*

View File

@ -1121,19 +1121,4 @@ public class CollUtilTest {
Assert.assertFalse(CollUtil.isEqualList(list, ListUtil.of(1, 2, 3)));
Assert.assertFalse(CollUtil.isEqualList(list, ListUtil.of(4, 3, 2, 1)));
}
@Test
public void isEqualsTest() {
final List<Integer> list = ListUtil.of(1, 2, 3, 4);
Assert.assertTrue(CollUtil.isEquals(null, null));
Assert.assertTrue(CollUtil.isEquals(ListUtil.of(), ListUtil.of()));
Assert.assertTrue(CollUtil.isEquals(list, list));
Assert.assertTrue(CollUtil.isEquals(list, ListUtil.of(1, 2, 3, 4)));
Assert.assertTrue(CollUtil.isEquals(list, ListUtil.of(4, 3, 2, 1)));
Assert.assertTrue(CollUtil.isEquals(list, SetUtil.of(4, 3, 2, 1)));
Assert.assertFalse(CollUtil.isEquals(null, ListUtil.of()));
Assert.assertFalse(CollUtil.isEquals(list, ListUtil.of(1, 2, 3, 3)));
Assert.assertFalse(CollUtil.isEquals(list, ListUtil.of(1, 2, 3)));
}
}