क्या सूची में बैचों को तोड़ने के लिए एक सामान्य जावा उपयोगिता है?


141

मैंने खुद को दी गई आकार के बैचों में एक सूची को तोड़ने के लिए एक उपयोगिता लिखी। मैं सिर्फ यह जानना चाहता था कि क्या इसके लिए पहले से कोई एपाचे कॉमन्स का उपयोग है या नहीं।

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;
}

कृपया मुझे बताएं कि क्या इसके लिए पहले से मौजूद कोई उपयोगिता है।


4
यकीन नहीं होता कि यह ऑफ टॉपिक है। सवाल यह नहीं है कि "पुस्तकालय यह क्या करता है" लेकिन "मैं अपाचे आम बर्तनों के साथ यह कैसे कर सकता हूं"।
फ्लोरियन एफ

@FlorianF मैं आपसे सहमत हूं। यह प्रश्न और इसके उत्तर बहुत उपयोगी हैं, और इसे एक छोटे से संपादन के साथ अच्छी तरह से बचाया जा सकता है। इसे जल्दबाजी में बंद करना एक लज़ीज़ कार्रवाई थी।
एंड्री

यहाँ अच्छी क्लास और बेंचमार्क के साथ उपयोगी ब्लॉग पोस्ट मिली: e.printstacktrace.blog/…
Benj

जवाबों:


250

की जाँच करें से गूगल अमरूद : Lists.partition(java.util.List, int)

किसी सूची के लगातार उप-सूची देता है, प्रत्येक समान आकार (अंतिम सूची छोटी हो सकती है)। उदाहरण के लिए, [a, b, c, d, e]3 पैदावार के विभाजन आकार के साथ एक सूची को विभाजित करना [[a, b, c], [d, e]]- एक बाहरी सूची जिसमें तीन और दो तत्वों की दो आंतरिक सूची शामिल हैं, सभी मूल क्रम में।


लिंक partition documentation और लिंक code example
ऑस्टिन हैव्स

16
Apache आम उपयोगकर्ताओं के लिए, यह फ़ंक्शन भी उपलब्ध है: commons.apache.org/proper/commons-collections/apidocs/org/…
Xavier Portebois

3
च आप एक सूची के साथ काम कर रहे हैं जो मैं "अपाचे कॉमन्स कलेक्शंस 4" लाइब्रेरी का उपयोग करता हूं। यह ListUtils वर्ग में एक विभाजन विधि है: ... int targetSize = 100; सूची <Integer> bigList = ... सूची <सूची <Integer >> आउटपुट = ListUtils.partition (bigList, targetSize); इस विधि को code.google.com/p/guava-lbooks
स्वप्निल जाजू

1
धन्यवाद। मैं विश्वास नहीं कर सकता कि यह जावा में कितना कठिन है।
चाचा लंबे बाल

51

यदि आप बैचों की जावा -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]

मैं इस दृष्टिकोण में कैसे टूटूं, जारी रहूं या वापस लौटूं?
मिरल

15

एक अन्य दृष्टिकोण 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]]


1
@ सीन यह सामान्य मामले के लिए काम करता है। groupingByके तत्वों पर किया जाता है IntStream.rangeसूची तत्वों, नहीं। जैसे देखें ideone.com/KYBc7h
रेडियोडफ

@MohammedElrashidy सेबियन ने उनकी टिप्पणी को हटा दिया है, अब आप उन्हें हटा सकते हैं।
अल्बर्ट हेंड्रिक्स

7

मैं इस एक के साथ आया:

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;
}

6

जावा 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]]

5

निम्नलिखित उदाहरण एक सूची का हिस्सा प्रदर्शित करता है:

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]]

4

था एक और सवाल यह है कि इस एक का डुप्लिकेट होने के रूप में बंद हो गया, लेकिन अगर आप इसे बारीकी से पढ़ें, यह आसानी से अलग है। इसलिए यदि कोई व्यक्ति (मेरे जैसा) वास्तव में एक सूची को लगभग समान आकार के सब्लिस्ट्स की सूची में विभाजित करना चाहता है , तो पढ़ें।

मैंने बस यहाँ वर्णित एल्गोरिदम को जावा में पोर्ट किया ।

@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);
}


3

वेब से विभिन्न धोखा देती है, मैं इस समाधान के लिए आया था:

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( ... );

4
एक AtomicIntegerगिनती के लिए उपयोग कर सकते हैं ।
jkschneider


1

धाराओं और लिबास के बिना ओपी के समान, लेकिन कंसीलर:

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;
}

0

इसे हल करने के लिए एक और दृष्टिकोण, प्रश्न:

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;
    }

}

0

जावा 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();

}

0

यहाँ जावा 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();
}

0

सूची का बैच प्राप्त करने के लिए आप नीचे दिए गए कोड का उपयोग कर सकते हैं।

Iterable<List<T>> batchIds = Iterables.partition(list, batchSize);

उपरोक्त कोड का उपयोग करने के लिए आपको Google अमरूद पुस्तकालय का आयात करना होगा।


-1

import com.google.common.collect.Lists;

List<List<T>> batches = Lists.partition(List<T>,batchSize)

सूची-सूची (सूची, बैचसाइज़) का उपयोग करें। आपको ListsGoogle सामान्य पैकेज ( com.google.common.collect.Lists) से आयात करना होगा

यह आपके List<T>साथ समान और प्रत्येक तत्व के आकार की सूची लौटाएगा batchSize


आप subList(startIndex, endIndex)आवश्यक इंडेक्स के आधार पर सूची को तोड़ने के लिए अपने स्वयं के तरीके का उपयोग कर सकते हैं ।
v87278
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.