Я написал себе утилиту, чтобы разбивать список на группы заданного размера. Я просто хотел узнать, есть ли для этого какие-либо утилиты apache commons.
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;
}
Пожалуйста, дайте мне знать, есть ли уже существующая утилита для того же самого.
java
collections
Хариш
источник
источник
Ответы:
Отъезд из Google Guava :
Lists.partition(java.util.List, int)
источник
partition documentation
и ссылкаcode example
Если вы хотите создать поток пакетов 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); }
Выход:
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);
Выход:
источник
groupingBy
делается для элементовIntStream.range
, а не для элементов списка. См., Например, ideone.com/KYBc7h .Я придумал вот это:
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; }
источник
В Java 9 вы можете использовать
IntStream.iterate()
с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()); }
При
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
использовании результатgetBatches(numbers, 4)
будет:[[0, 1, 2, 3], [4, 5, 6, 7], [8, 9]]
источник
Используйте Apache Commons ListUtils.partition .
org.apache.commons.collections4.ListUtils.partition(final List<T> list, final int size)
источник
В следующем примере демонстрируется разбиение списка на части:
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]]
источник
Был еще один вопрос, который был закрыт как дубликат этого, но если вы внимательно его прочитаете, он будет несколько отличаться. Так что, если кто-то (вроде меня) действительно хочет разбить список на заданное количество подсписок почти одинакового размера, продолжайте читать.
Я просто перенес описанный здесь алгоритм на Java.
@Test public void shouldPartitionListIntoAlmostEquallySizedSublists() { List<String> list = Arrays.asList("a", "b", "c", "d", "e", "f", "g"); int numberOfPartitions = 3; List<List<String>> split = IntStream.range(0, numberOfPartitions).boxed() .map(i -> list.subList( partitionOffset(list.size(), numberOfPartitions, i), partitionOffset(list.size(), numberOfPartitions, i + 1))) .collect(toList()); assertThat(split, hasSize(numberOfPartitions)); assertEquals(list.size(), split.stream().flatMap(Collection::stream).count()); assertThat(split, hasItems(Arrays.asList("a", "b", "c"), Arrays.asList("d", "e"), Arrays.asList("f", "g"))); } private static int partitionOffset(int length, int numberOfPartitions, int partitionIndex) { return partitionIndex * (length / numberOfPartitions) + Math.min(partitionIndex, length % numberOfPartitions); }
источник
Используя различные читы из Интернета, я пришел к такому решению:
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, чтобы имитировать нормальный индекс коллекции.
Затем мы группируем элементы коллекции в сегменты, используя алгебраический фактор как номер сегмента.
Окончательная карта содержит в качестве ключа номер сегмента, а в качестве значения - сам контейнер.
Затем вы можете легко выполнить операцию с каждым из сегментов с помощью:
источник
AtomicInteger
для подсчета.источник
Вот простое решение для Java 8+:
public static <T> Collection<List<T>> prepareChunks(List<T> inputList, int chunkSize) { AtomicInteger counter = new AtomicInteger(); return inputList.stream().collect(Collectors.groupingBy(it -> counter.getAndIncrement() / chunkSize)).values(); }
источник
Вы можете использовать приведенный ниже код, чтобы получить пакет списка.
Вам необходимо импортировать библиотеку Google Guava, чтобы использовать приведенный выше код.
источник
Подобно OP без потоков и библиотек, но более лаконично:
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);
Ввод: [A, B, C, D, E]
Вывод: [[A, B, C], [D, E]]
Вы можете найти примеры здесь: https://e.printstacktrace.blog/divide-a-list-to-lists-of-n-size-in-Java-8/
источник
Другой подход к решению этого вопроса:
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; } }
источник
Однострочник в 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(); }
источник
import com.google.common.collect.Lists;
List<List<T>> batches = Lists.partition(List<T>,batchSize)
Используйте Lists.partition (List, batchSize). Вам нужно импортировать
Lists
из общего пакета Google (com.google.common.collect.Lists
)Он вернет список
List<T>
с размером каждого элемента, равным вашемуbatchSize
.источник
subList(startIndex, endIndex)
метод разбиения списка на основе необходимого индекса.