add method

This commit is contained in:
Looly 2021-08-22 17:53:02 +08:00
parent 8be645e9fb
commit 40828f69d1
6 changed files with 138 additions and 34 deletions

View File

@ -15,9 +15,10 @@
* 【core 】 XmlUtil增加append重载issue#I466Q0@Gitee
* 【poi 】 增加EscapeStrCellSetterissue#I466ZZ@Gitee
* 【poi 】 ExcelBase增加renameSheet、cloneSheetissue#I466ZZ@Gitee
* 【core 】 修复MapUtil.sort比较器不一致返回原map的问题issue#I46AQJ@Gitee
* 【core 】 ListUtil增加splitAvg方法pr#397@Gitee
### 🐞Bug修复
* 【core 】 修复MapUtil.sort比较器不一致返回原map的问题issue#I46AQJ@Gitee
* 【core 】 修复JSONSupport默认循环引用导致的问题issue#1779@Github
-------------------------------------------------------------------------------------------------------------

View File

@ -0,0 +1,57 @@
package cn.hutool.core.collection;
import cn.hutool.core.lang.Assert;
import java.util.List;
/**
* 列表分区或分段<br>
* 通过传入分区个数将指定列表分区为不同的块每块区域的长度均匀分布个数差不超过1<br>
* <pre>
* [1,2,3,4] - [1,2], [3, 4]
* [1,2,3,4] - [1,2], [3], [4]
* [1,2,3,4] - [1], [2], [3], [4]
* [1,2,3,4] - [1], [2], [3], [4], []
* </pre>
* 分区是在原List的基础上进行的返回的分区是不可变的抽象列表原列表元素变更分区中元素也会变更
*
* @param <T> 元素类型
* @author looly
* @since 5.7.10
*/
public class AvgPartition<T> extends Partition<T> {
final int limit;
// 平均分完后剩余的个数平均放在前remainder个分区中
final int remainder;
/**
* 列表分区
*
* @param list 被分区的列表
* @param limit 分区个数
*/
public AvgPartition(List<T> list, int limit) {
super(list, list.size() / (limit <= 0 ? 1 : limit));
Assert.isTrue(limit > 0, "Partition limit must be > 0");
this.limit = limit;
this.remainder = list.size() % limit;
}
@Override
public List<T> get(int index) {
// 当limit个数超过list的size时size为0此时每个分区分1个元素直到remainder个分配完剩余分区为[]
int start = index * size + Math.min(index, remainder);
int end = start + size;
if (index + 1 <= remainder) {
// 将remainder个元素平均分布在前面每个分区分1个
end += 1;
}
return list.subList(start, end);
}
@Override
public int size() {
return limit;
}
}

View File

@ -8,7 +8,6 @@ import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.PageUtil;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
@ -538,7 +537,7 @@ public class ListUtil {
*/
public static <T> List<List<T>> partition(List<T> list, int size) {
if (CollUtil.isEmpty(list)) {
return Collections.emptyList();
return empty();
}
return (list instanceof RandomAccess)
@ -558,8 +557,8 @@ public class ListUtil {
* @param list 列表
* @param size 每个段的长度
* @return 分段列表
* @since 5.4.5
* @see #partition(List, int)
* @since 5.4.5
*/
public static <T> List<List<T>> split(List<T> list, int size) {
return partition(list, size);
@ -568,40 +567,27 @@ public class ListUtil {
/**
* 将集合平均分成多个list返回这个集合的列表
* <p></p>
* <blockquote><pre>
* ListUtil.splitAvg(null, 3); // [[], [], []]
* <pre>
* ListUtil.splitAvg(null, 3); // []
* ListUtil.splitAvg(Arrays.asList(1, 2, 3, 4), 2); // [[1, 2], [3, 4]]
* ListUtil.splitAvg(Arrays.asList(1, 2, 3), 5); // [[1], [2], [3], [], []]
* ListUtil.splitAvg(Arrays.asList(1, 2, 3), 2); // [[1, 2], [3]]
* </pre></blockquote>
* </pre>
*
* @param <T> 集合元素类型
* @param list 集合
* @param limit 要均分成几个list
* @return 分段列表
* @author lileming
* @since 5.7.10
*/
public static <T> List<List<T>> splitAvg(List<T> list, int limit) {
final List<List<T>> result = new ArrayList<>();
if (CollUtil.isEmpty(list)) {
for (int i = 0; i < limit; i++) {
result.add(new ArrayList<>());
return empty();
}
return result;
}
int remainder = list.size() % limit;
int number = list.size() / limit;
int offset = 0;
for (int i = 0; i < limit; i++) {
List<T> value;
if (remainder > 0) {
value = list.subList(i * number + offset, (i + 1) * number + offset + 1);
remainder--;
offset++;
} else {
value = list.subList(i * number + offset, (i + 1) * number + offset);
}
result.add(value);
}
return result;
return (list instanceof RandomAccess)
? new RandomAccessAvgPartition<>(list, limit)
: new AvgPartition<>(list, limit);
}
}

View File

@ -14,6 +14,7 @@ import java.util.List;
* @since 5.7.10
*/
public class Partition<T> extends AbstractList<List<T>> {
final List<T> list;
final int size;

View File

@ -0,0 +1,32 @@
package cn.hutool.core.collection;
import java.util.List;
import java.util.RandomAccess;
/**
* 列表分区或分段可随机访问列表<br>
* 通过传入分区个数将指定列表分区为不同的块每块区域的长度均匀分布个数差不超过1<br>
* <pre>
* [1,2,3,4] - [1,2], [3, 4]
* [1,2,3,4] - [1,2], [3], [4]
* [1,2,3,4] - [1], [2], [3], [4]
* [1,2,3,4] - [1], [2], [3], [4], []
* </pre>
* 分区是在原List的基础上进行的返回的分区是不可变的抽象列表原列表元素变更分区中元素也会变更
*
* @param <T> 元素类型
* @author looly
* @since 5.7.10
*/
public class RandomAccessAvgPartition<T> extends AvgPartition<T> implements RandomAccess {
/**
* 列表分区
*
* @param list 被分区的列表
* @param limit 分区个数
*/
public RandomAccessAvgPartition(List<T> list, int limit) {
super(list, limit);
}
}

View File

@ -9,13 +9,14 @@ import org.junit.Ignore;
import org.junit.Test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class ListUtilTest {
@Test
@Ignore
public void split() {
public void splitBenchTest() {
List<String> list = new ArrayList<>();
CollUtil.padRight(list, RandomUtil.randomInt(1000_0000, 1_0000_0000), "test");
@ -37,6 +38,32 @@ public class ListUtilTest {
Console.log(stopWatch.prettyPrint());
}
@Test
public void splitAvgTest(){
List<List<Object>> lists = ListUtil.splitAvg(null, 3);
Assert.assertEquals(ListUtil.empty(), lists);
lists = ListUtil.splitAvg(Arrays.asList(1, 2, 3, 4), 1);
Assert.assertEquals("[[1, 2, 3, 4]]", lists.toString());
lists = ListUtil.splitAvg(Arrays.asList(1, 2, 3, 4), 2);
Assert.assertEquals("[[1, 2], [3, 4]]", lists.toString());
lists = ListUtil.splitAvg(Arrays.asList(1, 2, 3, 4), 3);
Assert.assertEquals("[[1, 2], [3], [4]]", lists.toString());
lists = ListUtil.splitAvg(Arrays.asList(1, 2, 3, 4), 4);
Assert.assertEquals("[[1], [2], [3], [4]]", lists.toString());
lists = ListUtil.splitAvg(Arrays.asList(1, 2, 3), 5);
Assert.assertEquals("[[1], [2], [3], [], []]", lists.toString());
lists = ListUtil.splitAvg(Arrays.asList(1, 2, 3), 2);
Assert.assertEquals("[[1, 2], [3]]", lists.toString());
}
@Test(expected = IllegalArgumentException.class)
public void splitAvgNotZero(){
// limit不能小于等于0
ListUtil.splitAvg(Arrays.asList(1, 2, 3, 4), 0);
}
@Test
public void editTest(){
List<String> a = ListUtil.toLinkedList("1", "2", "3");