常用util将一个列表分成批处理
我给自己写了一个实用程序,把列表分成一个给定的大小。 我只是想知道,如果已经有任何的Apache公用事业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; }
请让我知道,如果有任何现有的util已经是相同的。
查看谷歌Guava的 Lists.partition(java.util.List, int)
:
返回列表的连续子列表,每个列表的大小相同(最终列表可能更小)。 例如,对分区大小为3的包含
[a, b, c, d, e]
进行分区产生[[a, b, c]
,[d, e]]
– 包含两个内部列表的三个和两个元素,都是按照原来的顺序。
如果你想产生一个Java-8批处理stream,你可以尝试下面的代码:
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); }
输出:
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]
另一种方法是使用Collectors.groupingBy
的索引,然后将分组索引映射到实际元素:
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,2,3,4,5,6,7,8,9,10,11]
[[1,2,3,4],[5,6,7,8],[9,10,11]]
下面的例子演示了一个List的分块:
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; } }
输出:
Ints: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11] Chunks: [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11]]
List<T> batch = collection.subList(i,i+nextInc); -> List<T> batch = collection.subList(i, i = i + nextInc);
从networking使用各种作弊,我来到这个解决scheme:
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 ); } ) );
我们用count来模仿正常的收集指数。
然后,我们将桶中的集合元素分组,使用代数商数作为桶号。
最终地图包含作为关键的桶号,作为桶本身的价值 。
然后您可以轻松地对每个桶执行操作:
chunkedUsers.values().forEach( ... );
I came up with this one: 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; }