Java 8 akış API'sında sayarak gruplama


170

Gruplama yapmak için Java 8 akışı API'sinde basit bir yol bulmaya çalışıyorum, bu karmaşık yolla çıkıyorum!

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

Katkınız için teşekkür ederim.


1
Burada neyi başarmaya çalışıyorsunuz?
Keppil

2
Bu çok yaygın bir durumdur, örnek Bir zaman diliminde bir hata oluştu ve bu zaman diliminde her gün başına düşen olay sayısı hakkında bazı istatistikler görmek istiyorum.
Muhammad Hewedy

Yanıtlar:


341

Ben sadece her grup ile ne yapacağını belirtmek için başka bir alır aşırı yük arıyoruz Collector... ve sonra Collectors.counting()sayma yapmak için:

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

Sonuç:

{Hello=2, World=1}

( groupingByConcurrentDaha fazla verimlilik için kullanma olasılığı da vardır . Bağlamınızda güvenli olacaksa, gerçek kodunuz için akılda tutulması gereken bir şey.)


1
Mükemmel! ... and then performing a reduction operation on the values associated with a given key using the specified downstream Collector
javadoc'tan

6
E -> e yerine Function.identity () (statik içe aktarma ile) kullanılması okumayı biraz daha hoş hale getirir: Map <String, Long> counted = list.stream (). Collect (groupingBy (identity (), counting () ));
Kuchi

Merhaba, Birisinin kodun Harita yönünü Map<String, Long> counted = list.stream() .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));, bu noktada tam olarak ne olduğunu ve gönderilebilecek konuyla ilgili daha fazla açıklama içeren bağlantıları açıklayabileceğini merak ediyordum
Boş

@Blank: bunun gibi hissediyor sanki bazı bölümleri hangi açıklayan birlikte, yeni bir soru olarak iyi olurdu Yani do ilk anlıyoruz. Her yönünü incelemek (hangi parçayı anlamadığınızı bilmemek) çok uzun zaman alacaktır - bu noktada, 5 yaşın üzerindeki bir cevaba koymak istediğimden daha fazla zaman, çoğunuz zaten anlayabilir.
Jon Skeet

@JonSkeet Cool, sorumda anlamadığım yönü vurgulasam da yeni bir soruya koyacağım. Bu, onunla birlikte eklediğim tüm kod snippet'i.
Boş

9

Nesnelerin listesi için örnek

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

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

İşte eldeki görevi gerçekleştirmek için biraz farklı seçenekler.

kullanarak toMap:

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

kullanarak Map::merge:

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

4

İşte StreamEx'in basit çözümü

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

Isıtıcı plaka kodunu azaltın: collect(Collectors.


1
Java8 akışları üzerinde kullanmanın nedeni nedir?
Torsten Ojaperv

1

Bir üçüncü taraf kitaplığı kullanarak açıksan kullanabileceğiniz Collectors2sınıfı Eclipse Koleksiyonu dönüştürmek için Listbir karşı Bagbir kullanma Stream. A Bag, saymak için oluşturulmuş bir veri yapısıdır .

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

Çıktı:

{World=1, Hello=2}

Bu özel durumda, sadece can doğrudan içine .collectListBag

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

Eclipse Collections protokollerini adapte ederek a'yı Bagkullanmadan da oluşturabilirsiniz .StreamList

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

veya bu özel durumda:

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

Ayrıca doğrudan Çanta oluşturabilirsiniz.

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

A Bag<String>, Map<String, Integer>dahili olarak anahtarları ve sayılarını takip ettiği bir a gibidir . Ancak, Mapbir anahtar içermediği bir anahtar sorarsanız , geri döner null. BagA'yı kullanarak içermediği bir anahtar sorarsanız occurrencesOf0 döndürür.

Not: Eclipse Collections için bir komisyoncuyum.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.