add method

This commit is contained in:
Looly 2022-04-17 08:53:43 +08:00
parent a8a866f35e
commit 7e36d0f076
7 changed files with 128 additions and 4 deletions

View File

@ -3,7 +3,7 @@
-------------------------------------------------------------------------------------------------------------
# 5.8.0.M4 (2022-04-16)
# 5.8.0.M4 (2022-04-17)
### ❌不兼容特性
* 【json 】 【可能兼容问题】JSONArray删除部分构造
@ -12,8 +12,10 @@
* 【core 】 BeanUtil增加toBean重载pr#598@Gitee
* 【json 】 新增JSONParser
* 【json 】 JSON新增在解析时的过滤方法issue#I52O85@Gitee
* 【core 】 添加ArrayUtil.distinct、CollUtil.distinct重载issue#2256@Github
### 🐞Bug修复
* 【core 】 修复StrUtil.firstNonX非static问题issue#2257@Github
-------------------------------------------------------------------------------------------------------------

View File

@ -1051,6 +1051,31 @@ public class CollUtil {
}
}
/**
* 根据函数生成的KEY去重集合如根据Bean的某个或者某些字段完成去重<br>
* 去重可选是保留最先加入的值还是后加入的值
*
* @param <T> 集合元素类型
* @param <K> 唯一键类型
* @param collection 集合
* @param override 是否覆盖模式如果为{@code true}加入的新值会覆盖相同key的旧值否则会忽略新加值
* @return {@link ArrayList}
* @since 5.8.0
*/
public static <T, K> List<T> distinct(Collection<T> collection, Function<T, K> uniqueGenerator, boolean override) {
if (isEmpty(collection)) {
return new ArrayList<>();
}
final UniqueKeySet<K, T> set = new UniqueKeySet<>(true, uniqueGenerator);
if (override) {
set.addAll(collection);
} else {
set.addAllIfAbsent(collection);
}
return new ArrayList<>(set);
}
/**
* 截取列表的部分
*

View File

@ -42,6 +42,17 @@ public class UniqueKeySet<K, V> extends AbstractSet<V> implements Serializable {
this(false, uniqueGenerator);
}
/**
* 构造
*
* @param uniqueGenerator 唯一键生成规则函数用于生成对象对应的唯一键
* @param c 初始化加入的集合
* @since 5.8.0
*/
public UniqueKeySet(Function<V, K> uniqueGenerator, Collection<? extends V> c) {
this(false, uniqueGenerator, c);
}
/**
* 构造
*
@ -52,6 +63,19 @@ public class UniqueKeySet<K, V> extends AbstractSet<V> implements Serializable {
this(MapBuilder.create(isLinked), uniqueGenerator);
}
/**
* 构造
*
* @param isLinked 是否保持加入顺序
* @param uniqueGenerator 唯一键生成规则函数用于生成对象对应的唯一键
* @param c 初始化加入的集合
* @since 5.8.0
*/
public UniqueKeySet(boolean isLinked, Function<V, K> uniqueGenerator, Collection<? extends V> c) {
this(isLinked, uniqueGenerator);
addAll(c);
}
/**
* 构造
*
@ -73,6 +97,7 @@ public class UniqueKeySet<K, V> extends AbstractSet<V> implements Serializable {
this.map = builder.build();
this.uniqueGenerator = uniqueGenerator;
}
//endregion
@Override

View File

@ -3879,7 +3879,7 @@ public class CharSequenceUtil {
* @since 5.4.1
*/
@SuppressWarnings("unchecked")
public <T extends CharSequence> T firstNonNull(T... strs) {
public static <T extends CharSequence> T firstNonNull(T... strs) {
return ArrayUtil.firstNonNull(strs);
}
@ -3893,7 +3893,7 @@ public class CharSequenceUtil {
* @since 5.4.1
*/
@SuppressWarnings("unchecked")
public <T extends CharSequence> T firstNonEmpty(T... strs) {
public static <T extends CharSequence> T firstNonEmpty(T... strs) {
return ArrayUtil.firstMatch(StrUtil::isNotEmpty, strs);
}
@ -3907,7 +3907,7 @@ public class CharSequenceUtil {
* @since 5.4.1
*/
@SuppressWarnings("unchecked")
public <T extends CharSequence> T firstNonBlank(T... strs) {
public static <T extends CharSequence> T firstNonBlank(T... strs) {
return ArrayUtil.firstMatch(StrUtil::isNotBlank, strs);
}

View File

@ -2,6 +2,7 @@ package cn.hutool.core.util;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.collection.UniqueKeySet;
import cn.hutool.core.comparator.CompareUtil;
import cn.hutool.core.exceptions.UtilException;
import cn.hutool.core.lang.Assert;
@ -1633,6 +1634,34 @@ public class ArrayUtil extends PrimitiveArrayUtil {
return toArray(set, (Class<T>) getComponentType(array));
}
/**
* 去重数组中的元素去重后生成新的数组原数组不变<br>
* 此方法通过{@link LinkedHashSet} 去重
*
* @param <T> 数组元素类型
* @param <K> 唯一键类型
* @param array 数组
* @param override 是否覆盖模式如果为{@code true}加入的新值会覆盖相同key的旧值否则会忽略新加值
* @return 去重后的数组
* @since 5.8.0
*/
@SuppressWarnings("unchecked")
public static <T, K> T[] distinct(T[] array, Function<T, K> uniqueGenerator, boolean override) {
if (isEmpty(array)) {
return array;
}
final UniqueKeySet<K, T> set = new UniqueKeySet<>(true, uniqueGenerator);
if(override){
Collections.addAll(set, array);
} else{
for (T t : array) {
set.addIfAbsent(t);
}
}
return toArray(set, (Class<T>) getComponentType(array));
}
/**
* 按照指定规则将一种类型的数组转换为另一种类型
*

View File

@ -878,6 +878,36 @@ public class CollUtilTest {
Assert.assertEquals(people.get(1).getGender(), "小孩");
}
@Test
public void distinctTest(){
final ArrayList<Integer> distinct = CollUtil.distinct(ListUtil.of(5, 3, 10, 9, 0, 5, 10, 9));
Assert.assertEquals(ListUtil.of(5, 3, 10, 9, 0), distinct);
}
@Test
public void distinctByFunctionTest(){
List<Person> people = Arrays.asList(
new Person("aa", 12, "man", 1),
new Person("bb", 13, "woman", 2),
new Person("cc", 14, "man", 3),
new Person("dd", 15, "woman", 4),
new Person("ee", 16, "woman", 5),
new Person("ff", 17, "man", 6)
);
// 覆盖模式下ff覆盖了aaee覆盖了bb
List<Person> distinct = CollUtil.distinct(people, Person::getGender, true);
Assert.assertEquals(2, distinct.size());
Assert.assertEquals("ff", distinct.get(0).getName());
Assert.assertEquals("ee", distinct.get(1).getName());
// 非覆盖模式下保留了最早加入的aa和bb
distinct = CollUtil.distinct(people, Person::getGender, false);
Assert.assertEquals(2, distinct.size());
Assert.assertEquals("aa", distinct.get(0).getName());
Assert.assertEquals("bb", distinct.get(1).getName());
}
@Data
@AllArgsConstructor
static class Person {

View File

@ -285,6 +285,19 @@ public class ArrayUtilTest {
Assert.assertArrayEquals(new String[]{"aa", "bb", "cc", "dd"}, distinct);
}
@Test
public void distinctByFunctionTest() {
String[] array = {"aa", "Aa", "BB", "bb"};
// 覆盖模式下保留最后加入的两个元素
String[] distinct = ArrayUtil.distinct(array, String::toLowerCase, true);
Assert.assertArrayEquals(new String[]{"Aa", "bb"}, distinct);
// 忽略模式下保留最早加入的两个元素
distinct = ArrayUtil.distinct(array, String::toLowerCase, false);
Assert.assertArrayEquals(new String[]{"aa", "BB"}, distinct);
}
@Test
public void toStingTest() {
int[] a = {1, 3, 56, 6, 7};