जावा 8 स्ट्रीम एपीआई में गिनती करके समूह


170

मैं समूहीकरण करने के लिए जावा 8 स्ट्रीम एपीआई में एक सरल तरीका खोजने की कोशिश करता हूं, मैं इस जटिल तरीके से बाहर आता हूं!

List<String> list = new ArrayList<>();

list.add("Hello");
list.add("Hello");
list.add("World");

Map<String, List<String>> collect = list.stream().collect(
        Collectors.groupingBy(o -> o));
System.out.println(collect);

List<String[]> collect2 = collect
        .entrySet()
        .stream()
        .map(e -> new String[] { e.getKey(),
                String.valueOf(e.getValue().size()) })
        .collect(Collectors.toList());

collect2.forEach(o -> System.out.println(o[0] + " >> " + o[1]));

मैं आपके इनपुट की सराहना करता हूं।


1
आप यहां क्या हासिल करने की कोशिश कर रहे हैं?
केपील

2
यह एक बहुत ही सामान्य मामला है, उदाहरण के लिए मैंने एक त्रुटि एक समय अवधि में होती है, और मैं इस समय अवधि में प्रत्येक दिन प्रति दिन की संख्या के बारे में कुछ आँकड़े देखना चाहता हूं।
मुहम्मद Hewedy

जवाबों:


340

मुझे लगता है कि आप सिर्फ अधिभार की तलाश कर रहे हैं जो Collectorयह बताने के लिए एक और लेता है कि प्रत्येक समूह के साथ क्या करना है ... और फिर Collectors.counting()गिनती करना है:

import java.util.*;
import java.util.stream.*;

class Test {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();

        list.add("Hello");
        list.add("Hello");
        list.add("World");

        Map<String, Long> counted = list.stream()
            .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));

        System.out.println(counted);
    }
}

परिणाम:

{Hello=2, World=1}

( groupingByConcurrentअधिक दक्षता के लिए उपयोग करने की संभावना भी है । आपके वास्तविक कोड के लिए कुछ ध्यान में रखना, अगर यह आपके संदर्भ में सुरक्षित होगा।)


1
उत्तम! ... and then performing a reduction operation on the values associated with a given key using the specified downstream Collector
जावदोक

6
ई -> ई के बजाय Function.identity () (स्थैतिक आयात के साथ) का उपयोग करना इसे पढ़ने के लिए थोड़ा अच्छा बनाता है: मैप <स्ट्रींग, लॉन्ग> काउंटेड = लिस्ट.स्ट्रीम ()। कलेक्टिंगबाय (पहचान ()), काउंटिंग ()। ));
कुची

नमस्ते, मैं सोच रहा था कि अगर कोई कोड के मानचित्र पहलू को समझा सकता है Map<String, Long> counted = list.stream() .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));, तो वास्तव में इस बिंदु पर क्या हो रहा है और किसी भी विषय के साथ जुड़े स्पष्टीकरण के साथ कोई लिंक जो भेजा जा सकता है
ब्लैंक

@Blank: यह की तरह महसूस करता आप समझा जो इसके कुछ हिस्सों आप के साथ एक नया सवाल के रूप में सबसे अच्छा है, हो सकता है कि है पहले समझते हैं। इसके हर पहलू से गुजरना (यह जानना कि आपको कौन सा बिट समझ में नहीं आता है) बहुत लंबा समय लगेगा - इससे अधिक समय कि मैं एक उत्तर देने को तैयार हूं जो इस बिंदु पर 5 साल से अधिक पुराना है, जब इसमें से अधिकांश पहले से ही समझ सकते हैं।
जॉन स्कीट

@JonSkeet कूल, मैं इसे एक नए प्रश्न में डालूँगा, हालाँकि मैंने उस पहलू को उजागर किया था जिसे मैं अपने प्रश्न में नहीं समझता था। यह होने के नाते, पूरे कोड स्निपेट मैंने इसके साथ जोड़े।
ब्लैंक

9
List<String> list = new ArrayList<>();

list.add("Hello");
list.add("Hello");
list.add("World");

Map<String, List<String>> collect = list.stream()
                                        .collect(Collectors.groupingBy(o -> o));
collect.entrySet()
       .forEach(e -> System.out.println(e.getKey() + " - " + e.getValue().size()));

8

यहाँ वस्तुओं की सूची के लिए उदाहरण है

Map<String, Long> requirementCountMap = requirements.stream().collect(Collectors.groupingBy(Requirement::getRequirementType, Collectors.counting()));

8

यहां कार्य को पूरा करने के लिए थोड़ा अलग विकल्प हैं।

का उपयोग कर toMap:

list.stream()
    .collect(Collectors.toMap(Function.identity(), e -> 1, Math::addExact));

का उपयोग कर Map::merge:

Map<String, Integer> accumulator = new HashMap<>();
list.forEach(s -> accumulator.merge(s, 1, Math::addExact));

4

यहाँ StreamEx द्वारा सरल समाधान है

StreamEx.of(list).groupingBy(Function.identity(), Collectors.countingInt());

बॉयलरप्लेट कोड को कम करें: collect(Collectors.


1
Java8 स्ट्रीम पर इसका उपयोग करने का क्या कारण है?
टॉर्स्ट ओजापर्व

1

यदि आप किसी तृतीय-पक्ष लायब्रेरी का उपयोग करने के लिए खुले हैं, तो आप ए का उपयोग कर कन्वर्ट करने के लिए ग्रहण संग्रहCollectors2 में कक्षा का उपयोग कर सकते हैं । ए एक डेटा संरचना है जिसे गिनती के लिए बनाया गया हैListBagStreamBag

Bag<String> counted =
        list.stream().collect(Collectors2.countBy(each -> each));

Assert.assertEquals(1, counted.occurrencesOf("World"));
Assert.assertEquals(2, counted.occurrencesOf("Hello"));

System.out.println(counted.toStringOfItemToCount());

आउटपुट:

{World=1, Hello=2}

इस विशेष मामले में, आप बस कर सकते हैं एक में सीधे ।collectListBag

Bag<String> counted = 
        list.stream().collect(Collectors2.toBag());

आप एक्लिप्स कलेक्शंस प्रोटोकॉल के साथ Bagप्रयोग करके भी बिना बना सकते हैं ।StreamList

Bag<String> counted = Lists.adapt(list).countBy(each -> each);

या इस विशेष मामले में:

Bag<String> counted = Lists.adapt(list).toBag();

तुम भी सीधे बैग बना सकते हैं।

Bag<String> counted = Bags.mutable.with("Hello", "Hello", "World");

A Bag<String>इस तरह Map<String, Integer>से है कि यह आंतरिक रूप से चाबियों और उनकी गिनती पर नज़र रखता है। लेकिन, यदि आप Mapएक कुंजी के लिए पूछते हैं जिसमें यह शामिल नहीं है, तो यह वापस आ जाएगी null। यदि आप Bagकिसी कुंजी का उपयोग करने के लिए कहते हैं occurrencesOf, तो इसमें 0 का उपयोग नहीं किया जाएगा।

नोट: मैं एक्लिप्स कलेक्शंस के लिए कमिट हूं।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.