是否有一个通用的Java实用程序可以将列表分为多个批?

是否有一个通用的Java实用程序可以将列表分为多个批?,java,collections,Java,Collections,我为自己编写了一个实用程序,可以将列表分成给定大小的批。我只是想知道是否已经有任何apachecommons-util用于此 public static <T> List<List<T>> getBatches(List<T> collection,int batchSize){ int i = 0; List<List<T>> batches = new ArrayList<List<T>

我为自己编写了一个实用程序,可以将列表分成给定大小的批。我只是想知道是否已经有任何apachecommons-util用于此

public static <T> List<List<T>> getBatches(List<T> collection,int batchSize){
    int i = 0;
    List<List<T>> batches = new ArrayList<List<T>>();
    while(i<collection.size()){
        int nextInc = Math.min(collection.size()-i,batchSize);
        List<T> batch = collection.subList(i,i+nextInc);
        batches.add(batch);
        i = i + nextInc;
    }

    return batches;
}
publicstaticlist-getBatches(列表集合,int-batchSize){
int i=0;
列表批次=新的ArrayList();
而(i从以下地址签出:

返回列表的连续子列表,每个子列表的大小相同(最终列表可能更小)。例如,将包含
[a,b,c,d,e]
的列表分区为3会产生
[[a,b,c]
[d,e]]
——一个外部列表,包含两个内部列表,由三个和两个元素组成,所有元素都按原始顺序排列

List batch=collection.subList(i,i+nextInc);
->
列表批次=集合。子列表(i,i=i+nextInc);

以下示例演示了列表的分块:

package de.thomasdarimont.labs;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class SplitIntoChunks {

    public static void main(String[] args) {

        List<Integer> ints = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11);

        List<List<Integer>> chunks = chunk(ints, 4);

        System.out.printf("Ints:   %s%n", ints);
        System.out.printf("Chunks: %s%n", chunks);
    }

    public static <T> List<List<T>> chunk(List<T> input, int chunkSize) {

        int inputSize = input.size();
        int chunkCount = (int) Math.ceil(inputSize / (double) chunkSize);

        Map<Integer, List<T>> map = new HashMap<>(chunkCount);
        List<List<T>> chunks = new ArrayList<>(chunkCount);

        for (int i = 0; i < inputSize; i++) {

            map.computeIfAbsent(i / chunkSize, (ignore) -> {

                List<T> chunk = new ArrayList<>();
                chunks.add(chunk);
                return chunk;

            }).add(input.get(i));
        }

        return chunks;
    }
}

如果要生成Java-8批处理流,可以尝试以下代码:

public static <T> Stream<List<T>> batches(List<T> source, int length) {
    if (length <= 0)
        throw new IllegalArgumentException("length = " + length);
    int size = source.size();
    if (size <= 0)
        return Stream.empty();
    int fullChunks = (size - 1) / length;
    return IntStream.range(0, fullChunks + 1).mapToObj(
        n -> source.subList(n * length, n == fullChunks ? size : (n + 1) * length));
}

public static void main(String[] args) {
    List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14);

    System.out.println("By 3:");
    batches(list, 3).forEach(System.out::println);
    
    System.out.println("By 4:");
    batches(list, 4).forEach(System.out::println);
}

通过使用网络上的各种欺骗手段,我得出了以下解决方案:

int[] count = new int[1];
final int CHUNK_SIZE = 500;
Map<Integer, List<Long>> chunkedUsers = users.stream().collect( Collectors.groupingBy( 
    user -> {
        count[0]++;
        return Math.floorDiv( count[0], CHUNK_SIZE );
    } )
);

我想到了这个:

private static <T> List<List<T>> partition(Collection<T> members, int maxSize)
{
    List<List<T>> res = new ArrayList<>();

    List<T> internal = new ArrayList<>();

    for (T member : members)
    {
        internal.add(member);

        if (internal.size() == maxSize)
        {
            res.add(internal);
            internal = new ArrayList<>();
        }
    }
    if (internal.isEmpty() == false)
    {
        res.add(internal);
    }
    return res;
}
私有静态列表分区(集合成员,int-maxSize)
{
List res=new ArrayList();
List internal=new ArrayList();
代表(T成员:成员)
{
内部。添加(成员);
if(internal.size()==maxSize)
{
决议增补(内部);
内部=新的ArrayList();
}
}
if(internal.isEmpty()==false)
{
决议增补(内部);
}
返回res;
}

另一种方法是使用
收集器。按索引进行分组,然后将分组的索引映射到实际元素:

    final List<Integer> numbers = range(1, 12)
            .boxed()
            .collect(toList());
    System.out.println(numbers);

    final List<List<Integer>> groups = range(0, numbers.size())
            .boxed()
            .collect(groupingBy(index -> index / 4))
            .values()
            .stream()
            .map(indices -> indices
                    .stream()
                    .map(numbers::get)
                    .collect(toList()))
            .collect(toList());
    System.out.println(groups);
最终列表编号=范围(1,12)
.boxed()
.collect(toList());
系统输出打印项次(数字);
最终列表组=范围(0,number.size())
.boxed()
.collect(分组方式(索引->索引/4))
.values()
.stream()
.map(索引->索引)
.stream()
.map(编号::get)
.collect(toList()))
.collect(toList());
系统输出打印项次(组);
输出:

Ints:   [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
Chunks: [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11]]
By 3:
[1, 2, 3]
[4, 5, 6]
[7, 8, 9]
[10, 11, 12]
[13, 14]
By 4:
[1, 2, 3, 4]
[5, 6, 7, 8]
[9, 10, 11, 12]
[13, 14]
[1,2,3,4,5,6,7,8,9,10,11]

[1,2,3,4],[5,6,7,8],[9,10,11]]

有一个被关闭,作为这个列表的副本,但如果你仔细阅读,它会有微妙的不同。所以,如果有人(像我一样)真的想将一个列表拆分为给定数量的几乎相同大小的子列表,请继续阅读

我只是将所描述的算法移植到Java

@测试
public void应将分区列表分为几乎完全相同的发布者(){
列表=数组。asList(“a”、“b”、“c”、“d”、“e”、“f”、“g”);
int numberOfPartitions=3;
List split=IntStream.range(0,numberOfPartitions).boxed()
.map(i->list.subList)(
partitionOffset(list.size(),numberOfPartitions,i),
partitionOffset(list.size(),numberOfPartitions,i+1)))
.collect(toList());
资产(拆分,hasSize(numberOfPartitions));
assertEquals(list.size()、split.stream().flatMap(Collection::stream.count());
资产(拆分,有项目(Arrays.asList(“a”、“b”、“c”)、Arrays.asList(“d”、“e”)、Arrays.asList(“f”、“g”));
}
私有静态int partitionOffset(int length、int numberOfPartitions、int partitionIndex){
返回partitionIndex*(长度/numberOfPartitions)+Math.min(partitionIndex,长度%numberOfPartitions);
}

解决这个问题的另一种方法:

public class CollectionUtils {

    /**
    * Splits the collection into lists with given batch size
    * @param collection to split in to batches
    * @param batchsize size of the batch
    * @param <T> it maintains the input type to output type
    * @return nested list
    */
    public static <T> List<List<T>> makeBatch(Collection<T> collection, int batchsize) {

        List<List<T>> totalArrayList = new ArrayList<>();
        List<T> tempItems = new ArrayList<>();

        Iterator<T> iterator = collection.iterator();

        for (int i = 0; i < collection.size(); i++) {
            tempItems.add(iterator.next());
            if ((i+1) % batchsize == 0) {
                totalArrayList.add(tempItems);
                tempItems = new ArrayList<>();
            }
        }

        if (tempItems.size() > 0) {
            totalArrayList.add(tempItems);
        }

        return totalArrayList;
    }

}
公共类集合utils{
/**
*将集合拆分为具有给定批量大小的列表
*@param集合要拆分为多个批次
*@param batchsize批处理的大小
*@param它将输入类型保持为输出类型
*@return嵌套列表
*/
公共静态列表makeBatch(集合集合,int batchsize){
List totalArrayList=新建ArrayList();
List tempItems=new ArrayList();
迭代器迭代器=collection.Iterator();
对于(int i=0;i0){
totalArrayList.add(临时项);
}
返回totalArrayList;
}
}
对于Java 9,您可以使用
hasNext
条件。因此,您可以将方法的代码简化为:

public static <T> List<List<T>> getBatches(List<T> collection, int batchSize) {
    return IntStream.iterate(0, i -> i < collection.size(), i -> i + batchSize)
            .mapToObj(i -> collection.subList(i, Math.min(i + batchSize, collection.size())))
            .collect(Collectors.toList());
}
使用apachecommons

org.apache.commons.collections4.ListUtils.partition(最终列表,最终整数大小)

导入com.google.common.collect.Lists;

List batches=Lists.partition(List,batchSize)

使用Lists.partition(List,batchSize)。您需要从google公共包(
com.google.common.collect.Lists
)导入
Lists


它将返回
List
列表,每个元素的大小等于
batchSize

Java 8中的一行代码是:

import static java.util.function.Function.identity;
import static java.util.stream.Collectors.*;

private static <T> Collection<List<T>> partition(List<T> xs, int size) {
    return IntStream.range(0, xs.size())
            .boxed()
            .collect(collectingAndThen(toMap(identity(), xs::get), Map::entrySet))
            .stream()
            .collect(groupingBy(x -> x.getKey() / size, mapping(Map.Entry::getValue, toList())))
            .values();

}
导入静态java.util.function.function.identity;
导入静态java.util.stream.Collectors.*;
私有静态集合分区(列表xs,整数大小){
返回IntStream.range(0,xs.size())
.boxed()
.collect(collectingAndThen(toMap(identity(),xs::get),Map::entrySet))
.stream()
.collect(groupingBy(x->x.getKey()/size,映射(Map.Entry::getValue,toList()))
.values();
}

以下是一个简单的Java 8+解决方案:

publicstaticcollection prepareChunks(List-inputList,int-chunkSize){
AtomicInteger计数器=新的AtomicInteger();
返回inputList.stream().collect(Collectors.groupingBy(it->counter.getAndIncrement()/chunkSize)).values();
}

您可以使用下面的代码获取列表批次

Iterable<List<T>> batchIds = Iterables.partition(list, batchSize);
Iterable batchIds=Iterabl
public static <T> List<List<T>> getBatches(List<T> collection, int batchSize) {
    return IntStream.iterate(0, i -> i < collection.size(), i -> i + batchSize)
            .mapToObj(i -> collection.subList(i, Math.min(i + batchSize, collection.size())))
            .collect(Collectors.toList());
}
[[0, 1, 2, 3], [4, 5, 6, 7], [8, 9]]
org.apache.commons.collections4.ListUtils.partition(final List<T> list, final int size)
import static java.util.function.Function.identity;
import static java.util.stream.Collectors.*;

private static <T> Collection<List<T>> partition(List<T> xs, int size) {
    return IntStream.range(0, xs.size())
            .boxed()
            .collect(collectingAndThen(toMap(identity(), xs::get), Map::entrySet))
            .stream()
            .collect(groupingBy(x -> x.getKey() / size, mapping(Map.Entry::getValue, toList())))
            .values();

}
Iterable<List<T>> batchIds = Iterables.partition(list, batchSize);
public <T> List<List<T>> getBatches(List<T> collection, int batchSize) {
    List<List<T>> batches = new ArrayList<>();
    for (int i = 0; i < collection.size(); i += batchSize) {
        batches.add(collection.subList(i, Math.min(i + batchSize, collection.size())));
    }
    return batches;
}
final AtomicInteger counter = new AtomicInteger();
final int partitionSize=3;
final List<Object> list=new ArrayList<>();
            list.add("A");
            list.add("B");
            list.add("C");
            list.add("D");
            list.add("E");
       
        
final Collection<List<Object>> subLists=list.stream().collect(Collectors.groupingBy
                (it->counter.getAndIncrement() / partitionSize))
                .values();
        System.out.println(subLists);