mirror of
https://gitee.com/chinabugotech/hutool.git
synced 2025-04-19 03:01:48 +08:00
add CollectionOperation
This commit is contained in:
parent
136cc3b08a
commit
0842ff0f50
@ -6,8 +6,8 @@ import cn.hutool.core.collection.iter.IteratorEnumeration;
|
||||
import cn.hutool.core.comparator.CompareUtil;
|
||||
import cn.hutool.core.comparator.PinyinComparator;
|
||||
import cn.hutool.core.comparator.PropertyComparator;
|
||||
import cn.hutool.core.convert.Convert;
|
||||
import cn.hutool.core.convert.CompositeConverter;
|
||||
import cn.hutool.core.convert.Convert;
|
||||
import cn.hutool.core.exceptions.UtilException;
|
||||
import cn.hutool.core.lang.hash.Hash32;
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
@ -297,63 +297,19 @@ public class CollUtil {
|
||||
return new ArrayList<>(set);
|
||||
}
|
||||
|
||||
/**
|
||||
* 两个集合的并集<br>
|
||||
* 针对一个集合中存在多个相同元素的情况,计算两个集合中此元素的个数,保留最多的个数<br>
|
||||
* 例如:集合1:[a, b, c, c, c],集合2:[a, b, c, c]<br>
|
||||
* 结果:[a, b, c, c, c],此结果中只保留了三个c
|
||||
*
|
||||
* @param <T> 集合元素类型
|
||||
* @param coll1 集合1
|
||||
* @param coll2 集合2
|
||||
* @return 并集的集合,返回 {@link ArrayList}
|
||||
*/
|
||||
public static <T> Collection<T> union(final Collection<T> coll1, final Collection<T> coll2) {
|
||||
if (isEmpty(coll1)) {
|
||||
return ListUtil.of(coll2);
|
||||
} else if (isEmpty(coll2)) {
|
||||
return ListUtil.of(coll1);
|
||||
}
|
||||
|
||||
// 给每个元素计数
|
||||
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());
|
||||
// 并集, 每个元素至少会有一个
|
||||
final List<T> list = new ArrayList<>(elements.size());
|
||||
for (final T t : elements) {
|
||||
// 每个元素 保留最多的个数
|
||||
int amount = Math.max(map1.getOrDefault(t, 0), map2.getOrDefault(t, 0));
|
||||
for (int i = 0; i < amount; i++) {
|
||||
list.add(t);
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* 多个集合的并集<br>
|
||||
* 针对一个集合中存在多个相同元素的情况,计算两个集合中此元素的个数,保留最多的个数<br>
|
||||
* 例如:集合1:[a, b, c, c, c],集合2:[a, b, c, c]<br>
|
||||
* 结果:[a, b, c, c, c],此结果中只保留了三个c
|
||||
*
|
||||
* @param <T> 集合元素类型
|
||||
* @param coll1 集合1
|
||||
* @param coll2 集合2
|
||||
* @param otherColls 其它集合
|
||||
* @param <T> 集合元素类型
|
||||
* @param colls 集合数组
|
||||
* @return 并集的集合,返回 {@link ArrayList}
|
||||
*/
|
||||
@SafeVarargs
|
||||
public static <T> Collection<T> union(final Collection<T> coll1, final Collection<T> coll2, final Collection<T>... otherColls) {
|
||||
Collection<T> union = union(coll1, coll2);
|
||||
for (final Collection<T> coll : otherColls) {
|
||||
if (isNotEmpty(coll)) {
|
||||
union = union(union, coll);
|
||||
}
|
||||
}
|
||||
return union;
|
||||
public static <T> Collection<T> union(final Collection<T>... colls) {
|
||||
return CollectionOperation.of(colls).union();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -362,34 +318,13 @@ public class CollUtil {
|
||||
* 例如:集合1:[a, b, c, c, c],集合2:[a, b, c, c]<br>
|
||||
* 结果:[a, b, c],此结果中只保留了一个c
|
||||
*
|
||||
* @param <T> 集合元素类型
|
||||
* @param coll1 集合1
|
||||
* @param coll2 集合2
|
||||
* @param otherColls 其它集合
|
||||
* @param <T> 集合元素类型
|
||||
* @param colls 列表集合
|
||||
* @return 并集的集合,返回 {@link LinkedHashSet}
|
||||
*/
|
||||
@SafeVarargs
|
||||
public static <T> Set<T> unionDistinct(final Collection<T> coll1, final Collection<T> coll2, final Collection<T>... otherColls) {
|
||||
final Set<T> result;
|
||||
if (isEmpty(coll1)) {
|
||||
result = new LinkedHashSet<>();
|
||||
} else {
|
||||
result = new LinkedHashSet<>(coll1);
|
||||
}
|
||||
|
||||
if (isNotEmpty(coll2)) {
|
||||
result.addAll(coll2);
|
||||
}
|
||||
|
||||
if (ArrayUtil.isNotEmpty(otherColls)) {
|
||||
for (final Collection<T> otherColl : otherColls) {
|
||||
if (isNotEmpty(otherColl)) {
|
||||
result.addAll(otherColl);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
public static <T> Set<T> unionDistinct(final Collection<T>... colls) {
|
||||
return CollectionOperation.of(colls).unionDistinct();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -398,73 +333,13 @@ public class CollUtil {
|
||||
* 例如:集合1:[a, b, c, c, c],集合2:[a, b, c, c]<br>
|
||||
* 结果:[a, b, c, c, c, a, b, c, c]
|
||||
*
|
||||
* @param <T> 集合元素类型
|
||||
* @param coll1 集合1
|
||||
* @param coll2 集合2
|
||||
* @param otherColls 其它集合
|
||||
* @param <T> 集合元素类型
|
||||
* @param colls 集合数组
|
||||
* @return 并集的集合,返回 {@link ArrayList}
|
||||
*/
|
||||
@SafeVarargs
|
||||
public static <T> List<T> unionAll(final Collection<T> coll1, final Collection<T> coll2, final Collection<T>... otherColls) {
|
||||
// 先统计所有集合的元素数量, 避免扩容
|
||||
int totalSize = size(coll1) + size(coll2);
|
||||
for (Collection<T> coll : otherColls) {
|
||||
totalSize += size(coll);
|
||||
}
|
||||
if (totalSize == 0) {
|
||||
return ListUtil.zero();
|
||||
}
|
||||
final List<T> result = new ArrayList<>(totalSize);
|
||||
|
||||
if (isNotEmpty(coll1)) {
|
||||
result.addAll(coll1);
|
||||
}
|
||||
if (isNotEmpty(coll2)) {
|
||||
result.addAll(coll2);
|
||||
}
|
||||
|
||||
if (ArrayUtil.isNotEmpty(otherColls)) {
|
||||
for (final Collection<T> otherColl : otherColls) {
|
||||
if (isNotEmpty(otherColl)) {
|
||||
result.addAll(otherColl);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 两个集合的交集<br>
|
||||
* 针对一个集合中存在多个相同元素的情况,计算两个集合中此元素的个数,保留最少的个数<br>
|
||||
* 例如:集合1:[a, b, c, c, c],集合2:[a, b, c, c]<br>
|
||||
* 结果:[a, b, c, c],此结果中只保留了两个c
|
||||
*
|
||||
* @param <T> 集合元素类型
|
||||
* @param coll1 集合1
|
||||
* @param coll2 集合2
|
||||
* @return 交集的集合,返回 {@link ArrayList}
|
||||
*/
|
||||
public static <T> Collection<T> intersection(final Collection<T> coll1, final Collection<T> coll2) {
|
||||
if (isNotEmpty(coll1) && isNotEmpty(coll2)) {
|
||||
final Map<T, Integer> map1 = countMap(coll1);
|
||||
final Map<T, Integer> map2 = countMap(coll2);
|
||||
|
||||
boolean isFirstSmaller = map1.keySet().size() <= map2.keySet().size();
|
||||
// 只需要遍历数量较少的集合的元素
|
||||
final Set<T> elements = SetUtil.of(isFirstSmaller ? map1.keySet() : map2.keySet());
|
||||
// 交集的元素个数 最多为 较少集合的元素个数
|
||||
final List<T> list = new ArrayList<>(isFirstSmaller ? coll1.size() : coll2.size());
|
||||
for (final T t : elements) {
|
||||
int amount = Math.min(map1.getOrDefault(t, 0), map2.getOrDefault(t, 0));
|
||||
for (int i = 0; i < amount; i++) {
|
||||
list.add(t);
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
return ListUtil.zero();
|
||||
public static <T> List<T> unionAll(final Collection<T>... colls) {
|
||||
return CollectionOperation.of(colls).unionAll();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -473,26 +348,13 @@ public class CollUtil {
|
||||
* 例如:集合1:[a, b, c, c, c],集合2:[a, b, c, c]<br>
|
||||
* 结果:[a, b, c, c],此结果中只保留了两个c
|
||||
*
|
||||
* @param <T> 集合元素类型
|
||||
* @param coll1 集合1
|
||||
* @param coll2 集合2
|
||||
* @param otherColls 其它集合
|
||||
* @param <T> 集合元素类型
|
||||
* @param colls 集合列表
|
||||
* @return 交集的集合,返回 {@link ArrayList}
|
||||
*/
|
||||
@SafeVarargs
|
||||
public static <T> Collection<T> intersection(final Collection<T> coll1, final Collection<T> coll2, final Collection<T>... otherColls) {
|
||||
// 任意容器为空, 则返回空集
|
||||
if (isEmpty(coll1) || isEmpty(coll2) || ArrayUtil.hasEmpty((Object[]) otherColls)) {
|
||||
return ListUtil.zero();
|
||||
}
|
||||
Collection<T> intersection = intersection(coll1, coll2);
|
||||
if (ArrayUtil.isEmpty(otherColls)) {
|
||||
return intersection;
|
||||
}
|
||||
for (final Collection<T> coll : otherColls) {
|
||||
intersection = intersection(intersection, coll);
|
||||
}
|
||||
return intersection;
|
||||
public static <T> Collection<T> intersection(final Collection<T>... colls) {
|
||||
return CollectionOperation.of(colls).intersection();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -563,7 +425,7 @@ public class CollUtil {
|
||||
elements.addAll(map2.keySet());
|
||||
// 元素的个数为 该元素在两个集合中的个数的差
|
||||
for (final T t : elements) {
|
||||
int amount = Math.abs(map1.getOrDefault(t, 0) - map2.getOrDefault(t, 0));
|
||||
final int amount = Math.abs(map1.getOrDefault(t, 0) - map2.getOrDefault(t, 0));
|
||||
for (int i = 0; i < amount; i++) {
|
||||
result.add(t);
|
||||
}
|
||||
@ -691,7 +553,7 @@ public class CollUtil {
|
||||
if (isEmpty(coll1) || isEmpty(coll2)) {
|
||||
return false;
|
||||
}
|
||||
boolean isFirstSmaller = coll1.size() <= coll2.size();
|
||||
final boolean isFirstSmaller = coll1.size() <= coll2.size();
|
||||
// 用元素较少的集合来遍历
|
||||
final Collection<?> smallerColl = isFirstSmaller ? coll1 : coll2;
|
||||
// 用元素较多的集合构造Set, 用于快速判断是否有相同元素
|
||||
@ -2333,7 +2195,7 @@ public class CollUtil {
|
||||
}
|
||||
// 统计每个map的values的大小总和
|
||||
int size = 0;
|
||||
for (Map<?, V> map : mapCollection) {
|
||||
for (final Map<?, V> map : mapCollection) {
|
||||
size += size(map.values());
|
||||
}
|
||||
if (size == 0) {
|
||||
@ -2611,7 +2473,7 @@ public class CollUtil {
|
||||
//noinspection unchecked
|
||||
final Map<Object, Integer> countMap1 = countMap((Iterable<Object>) coll1);
|
||||
|
||||
for (Object e : coll2) {
|
||||
for (final Object e : coll2) {
|
||||
// 该元素若存在, 则个数减去1, 若不存在则个数为-1
|
||||
final Integer amount = countMap1.merge(e, -1, Integer::sum);
|
||||
if (amount < 0) {
|
||||
|
209
hutool-core/src/main/java/cn/hutool/core/collection/CollectionOperation.java
Executable file
209
hutool-core/src/main/java/cn/hutool/core/collection/CollectionOperation.java
Executable file
@ -0,0 +1,209 @@
|
||||
package cn.hutool.core.collection;
|
||||
|
||||
import cn.hutool.core.util.ArrayUtil;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 集合运算
|
||||
*
|
||||
* @param <E> 集合元素类型
|
||||
*/
|
||||
public class CollectionOperation<E> {
|
||||
|
||||
@SafeVarargs
|
||||
public static <E> CollectionOperation<E> of(final Collection<E>... colls) {
|
||||
return new CollectionOperation<>(colls);
|
||||
}
|
||||
|
||||
private final Collection<E>[] colls;
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param colls 集合数组
|
||||
*/
|
||||
public CollectionOperation(final Collection<E>[] colls) {
|
||||
this.colls = colls;
|
||||
}
|
||||
|
||||
/**
|
||||
* 多个集合的并集<br>
|
||||
* 针对一个集合中存在多个相同元素的情况,计算两个集合中此元素的个数,保留最多的个数<br>
|
||||
* 例如:集合1:[a, b, c, c, c],集合2:[a, b, c, c]<br>
|
||||
* 结果:[a, b, c, c, c],此结果中只保留了三个c
|
||||
*
|
||||
* @return 并集的集合,返回 {@link ArrayList}
|
||||
*/
|
||||
public Collection<E> union() {
|
||||
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 = _union(result, colls[i]);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 多个集合的非重复并集,类似于SQL中的“UNION DISTINCT”<br>
|
||||
* 针对一个集合中存在多个相同元素的情况,只保留一个<br>
|
||||
* 例如:集合1:[a, b, c, c, c],集合2:[a, b, c, c]<br>
|
||||
* 结果:[a, b, c],此结果中只保留了一个c
|
||||
*
|
||||
* @return 并集的集合,返回 {@link LinkedHashSet}
|
||||
*/
|
||||
public Set<E> unionDistinct() {
|
||||
final Collection<E>[] colls = this.colls;
|
||||
int totalLength = 0;
|
||||
for (final Collection<E> set : colls) {
|
||||
if (CollUtil.isNotEmpty(set)) {
|
||||
totalLength += set.size();
|
||||
}
|
||||
}
|
||||
final Set<E> result = new HashSet<>(totalLength, 1);
|
||||
for (final Collection<E> set : colls) {
|
||||
if (CollUtil.isNotEmpty(set)) {
|
||||
result.addAll(set);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 多个集合的完全并集,类似于SQL中的“UNION ALL”<br>
|
||||
* 针对一个集合中存在多个相同元素的情况,保留全部元素<br>
|
||||
* 例如:集合1:[a, b, c, c, c],集合2:[a, b, c, c]<br>
|
||||
* 结果:[a, b, c, c, c, a, b, c, c]
|
||||
*
|
||||
* @return 并集的集合,返回 {@link ArrayList}
|
||||
*/
|
||||
public List<E> unionAll() {
|
||||
final Collection<E>[] colls = this.colls;
|
||||
if (ArrayUtil.isEmpty(colls)) {
|
||||
return ListUtil.zero();
|
||||
}
|
||||
// 先统计所有集合的元素数量, 避免扩容
|
||||
int totalSize = 0;
|
||||
for (final Collection<E> coll : colls) {
|
||||
if (CollUtil.isNotEmpty(coll)) {
|
||||
totalSize += CollUtil.size(coll);
|
||||
}
|
||||
}
|
||||
if (totalSize == 0) {
|
||||
return ListUtil.zero();
|
||||
}
|
||||
|
||||
// 遍历并全部加入集合
|
||||
final List<E> result = new ArrayList<>(totalSize);
|
||||
for (final Collection<E> coll : colls) {
|
||||
if (CollUtil.isNotEmpty(coll)) {
|
||||
result.addAll(coll);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 多个集合的交集<br>
|
||||
* 针对一个集合中存在多个相同元素的情况,计算两个集合中此元素的个数,保留最少的个数<br>
|
||||
* 例如:集合1:[a, b, c, c, c],集合2:[a, b, c, c]<br>
|
||||
* 结果:[a, b, c, c],此结果中只保留了两个c
|
||||
*
|
||||
* @return 交集的集合,返回 {@link ArrayList}
|
||||
*/
|
||||
public Collection<E> intersection() {
|
||||
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 = _intersection(result, colls[i]);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 两个集合的并集<br>
|
||||
* 针对一个集合中存在多个相同元素的情况,计算两个集合中此元素的个数,保留最多的个数<br>
|
||||
* 例如:集合1:[a, b, c, c, c],集合2:[a, b, c, c]<br>
|
||||
* 结果:[a, b, c, c, c],此结果中只保留了三个c<br>
|
||||
* 结果集合与原集合顺序无关
|
||||
*
|
||||
* @param <T> 集合元素类型
|
||||
* @param coll1 集合1
|
||||
* @param coll2 集合2
|
||||
* @return 并集的集合,返回 {@link ArrayList}
|
||||
*/
|
||||
private static <T> Collection<T> _union(final Collection<T> coll1, final Collection<T> coll2) {
|
||||
if (CollUtil.isEmpty(coll1)) {
|
||||
return ListUtil.of(coll2);
|
||||
} else if (CollUtil.isEmpty(coll2)) {
|
||||
return ListUtil.of(coll1);
|
||||
}
|
||||
|
||||
// 给每个元素计数
|
||||
final Map<T, Integer> map1 = CollUtil.countMap(coll1);
|
||||
final Map<T, Integer> map2 = CollUtil.countMap(coll2);
|
||||
|
||||
// 两个集合的全部元素
|
||||
final Set<T> elements = CollectionOperation.of(map1.keySet(), map2.keySet()).unionDistinct();
|
||||
|
||||
// 并集, 每个元素至少会有一个
|
||||
final List<T> list = new ArrayList<>(coll1.size() + coll2.size());
|
||||
for (final T t : elements) {
|
||||
// 每个元素 保留最多的个数
|
||||
final int amount = Math.max(map1.getOrDefault(t, 0), map2.getOrDefault(t, 0));
|
||||
for (int i = 0; i < amount; i++) {
|
||||
list.add(t);
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* 两个集合的交集<br>
|
||||
* 针对一个集合中存在多个相同元素的情况,计算两个集合中此元素的个数,保留最少的个数<br>
|
||||
* 例如:集合1:[a, b, c, c, c],集合2:[a, b, c, c]<br>
|
||||
* 结果:[a, b, c, c],此结果中只保留了两个c
|
||||
*
|
||||
* @param <E> 集合元素类型
|
||||
* @param coll1 集合1
|
||||
* @param coll2 集合2
|
||||
* @return 交集的集合,返回 {@link ArrayList}
|
||||
*/
|
||||
private static <E> Collection<E> _intersection(final Collection<E> coll1, final Collection<E> coll2) {
|
||||
if (CollUtil.isEmpty(coll1) || CollUtil.isEmpty(coll2)) {
|
||||
return ListUtil.zero();
|
||||
}
|
||||
final Map<E, Integer> map1 = CollUtil.countMap(coll1);
|
||||
final Map<E, Integer> map2 = CollUtil.countMap(coll2);
|
||||
|
||||
final boolean isFirstSmaller = map1.size() <= map2.size();
|
||||
// 只需要遍历数量较少的集合的元素
|
||||
final Set<E> elements = SetUtil.of(isFirstSmaller ? map1.keySet() : map2.keySet());
|
||||
// 交集的元素个数 最多为 较少集合的元素个数
|
||||
final List<E> list = new ArrayList<>(isFirstSmaller ? coll1.size() : coll2.size());
|
||||
for (final E t : elements) {
|
||||
final int amount = Math.min(map1.getOrDefault(t, 0), map2.getOrDefault(t, 0));
|
||||
for (int i = 0; i < amount; i++) {
|
||||
list.add(t);
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
}
|
@ -192,6 +192,7 @@ public class SetUtil {
|
||||
* @param <T> 元素类型
|
||||
* @param c 集合
|
||||
* @return 只读集合
|
||||
* @see Collections#unmodifiableSet(Set)
|
||||
* @since 6.0.0
|
||||
*/
|
||||
public static <T> Set<T> unmodifiable(final Set<? extends T> c) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user