Java 8ストリームAPIでカウントしてグループ化する


170

Java 8ストリームAPIでグループ化を行う簡単な方法を見つけようとすると、この複雑な方法が出てきます。

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
ここで何を達成しようとしていますか?
ケッピル2014

2
これは非常に一般的なケースです。たとえば、ある期間にエラーが発生し、この期間の毎日の発生回数に関する統計を確認したいとします。
Muhammad Hewedy 2014

回答:


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
パーフェクト!... javadocからand then performing a reduction operation on the values associated with a given key using the specified downstream Collector
Muhammad Hewedy 14

6
e-> eの代わりにFunction.identity()(静的インポートを使用)を使用すると、読みやすくなります:Map <String、Long> count = list.stream()。collect(groupingBy(identity()、counting() ));
Kuchi

こんにちは、誰かがコードのマップの側面を説明できるかどうかMap<String, Long> counted = list.stream() .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));、この時点で正確に何が起こっているのか、送信できるトピックに関連する詳細な説明へのリンク
ブランク

@Blank:それのようなと感じているあなたは、あなたがそれの部分を説明すると、新しい質問として最高のだろう最初に理解しています。それのすべての側面を通過する(理解できないビットがわからない)には、非常に長い時間がかかります。この時点で5年以上経過している回答に、私が喜んで回答するよりも長い時間がかかります。すでに理解しているかもしれません。
Jon Skeet、

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


1

あなたは、サードパーティのライブラリを使用する開いている場合は、使用することができますCollectors2内のクラスのEclipseコレクションを変換するためListBag使用しましたStream。A Bagは、カウント用に構築されたデータ構造です。

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}

この特定のケースではcollectList直接に直接入れることができますBag

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

をEclipseコレクションプロトコルに適合させることにより、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ます。Bagusingを含まないキーをに要求すると、occurrencesOf0が返されます。

注:私はEclipseコレクションのコミッターです。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.