목록을 일괄적으로 분류할 수 있는 일반적인 Java 유틸리티가 있습니까?
나는 목록을 정해진 크기의 묶음으로 나누기 위한 유틸리티를 스스로 썼다.나는 단지 이것에 대한 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;
}
이미 같은 유틸리티가 있는지 알려주세요.
Google Guava에서 확인Lists.partition(java.util.List, int)
:
각각 크기가 동일한 연속된 목록의 하위 목록을 반환합니다(최종 목록은 더 작을 수 있음).예를 들어, 다음을 포함하는 목록 분할
[a, b, c, d, e]
, 「3」이 됩니다.[[a, b, c]
,[d, e]]
-- 순서로 되어 있는 -- 외 -- 、 3 、 2 、 2 개 -- -- -- -- -- 。
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]
Apache Commons ListUtils.partition을 사용합니다.
org.apache.commons.collections4.ListUtils.partition(final List<T> list, final int size)
하나의 은 '보다 낫다'입니다.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]]
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());
}
「」를 사용합니다.{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
의, 」getBatches(numbers, 4)
음음음같 뭇매하다
[[0, 1, 2, 3], [4, 5, 6, 7], [8, 9]]
내가 생각해낸 건 이거야
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;
}
다음 예시는 목록의 청킹을 보여 줍니다.
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 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();
}
다음은 예를 제시하겠습니다.
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-size-in-Java-8/의 예를 참조하십시오.
이 질문의 중복으로 종결된 질문이 하나 더 있었지만 자세히 읽어보면 약간 다릅니다.따라서 (나 같은) 누군가가 실제로 목록을 거의 동일한 크기의 하위 목록으로 분할하고 싶은 경우 계속 읽어보십시오.
여기 설명된 알고리즘을 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 );
} )
);
일반 수집 인덱스를 모방하기 위해 카운트를 사용합니다.
그런 다음 버킷 번호로 대수적 지수를 사용하여 수집 요소를 버킷으로 그룹화합니다.
마지막 맵에는 버킷 번호의 키와 버킷 자체의 값이 포함됩니다.
다음으로 각 버킷에 대한 작업을 쉽게 수행할 수 있습니다.
chunkedUsers.values().forEach( ... );
스트림과 리브가 없는 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;
}
List<T> batch = collection.subList(i,i+nextInc);
->
List<T> batch = collection.subList(i, i = i + nextInc);
주의:List#subList()
기본 컬렉션의 보기를 반환합니다. 이 경우 작은 목록을 편집할 때 예기치 않은 결과가 발생할 수 있습니다. 편집 내용은 원래 컬렉션에 반영되거나 느려질 수 있습니다.ConcurrentModificationException
.
이 문제를 해결하기 위한 또 다른 접근법은 다음과 같습니다.
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();
}
아래 코드를 사용하여 목록 배치를 가져올 수 있습니다.
Iterable<List<T>> batchIds = Iterables.partition(list, batchSize);
위의 코드를 사용하려면 Google Guava 라이브러리를 가져와야 합니다.
다음은 vanilla java와 super secret modulo 연산자를 사용한 솔루션입니다.
청크의 내용/순서는 중요하지 않기 때문에 이것이 가장 쉬운 방법입니다(멀티 스레드용으로 준비할 때는 보통 어떤 요소가 어떤 스레드에서 처리되는지 등 균등한 분배가 필요합니다).
public static <T> List<T>[] chunk(List<T> input, int chunkCount) {
List<T>[] chunks = new List[chunkCount];
for (int i = 0; i < chunkCount; i++) {
chunks[i] = new LinkedList<T>();
}
for (int i = 0; i < input.size(); i++) {
chunks[i % chunkCount].add(input.get(i));
}
return chunks;
}
사용방법:
List<String> list = Arrays.asList("a", "b", "c", "d", "e", "f", "g", "h", "i", "j");
List<String>[] chunks = chunk(list, 4);
for (List<String> chunk : chunks) {
System.out.println(chunk);
}
출력:
[a, e, i]
[b, f, j]
[c, g]
[d, h]
import com.google.common.collect.Lists;
List<List<T>> batches = Lists.partition(List<T>,batchSize)
Lists.partition(List, batch Size)을 사용합니다.Import가 필요합니다.Lists
google 공통 패키지(com.google.common.collect.Lists
)
다음 목록이 반환됩니다.List<T>
그리고 모든 요소의 크기가 당신의 것과 같다.batchSize
.
언급URL : https://stackoverflow.com/questions/12026885/is-there-a-common-java-utility-to-break-a-list-into-batches
'programing' 카테고리의 다른 글
EOF를 C코드로 나타냅니까? (0) | 2022.07.12 |
---|---|
폼 전송 후 화면 새로고침(Vue.js) (0) | 2022.07.11 |
Java에서 현재 스택트레이스를 취득하려면 어떻게 해야 하나요? (0) | 2022.07.11 |
Vue 컴포넌트의 양방향 데이터 흐름 (0) | 2022.07.11 |
새 창에서 VueJS 구성 요소 열기 (0) | 2022.07.11 |