3
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

「Dictの値をキーにキーを集計し、集計されたキーに対して任意の関数を実行したDictを返す」をJava8でやってみたら「[Java 8][Stream API] オブジェクトの List から Map を生成する方法を模索する」がすっきり書けた

Last updated at Posted at 2014-12-12

@keithseahus さんの Dictの値をキーにキーを集計し、集計されたキーに対して任意の関数を実行したDictを返す というElixir に関する投稿を読んだ。
Elixirの事は全く知らないけど、これJava8のStreamAPIだとどうなるんだろうと思ったのでやってみた。

やってること

Dict(JavaでいうとMap)のキーと値を入れ替えたDictの作成。
HadoopでいうとInverseMapper

元投稿によるとElixirではEnum.group_by/3というのがあるらしい。
これはJava8のCollectors.groupingBy(Function super T,? extends K> classifier)に相当するもので、これだと値をマップ(変換)する手段がないのでgroup_byを拡張したということらしい。

Java8でやってみた

Java8のCollectorsにはgroupingBy(Function super T,? extends K> classifier, Collector super T,A,D> downstreamというのもあって、値のマップもできるのでこれを使ってみた。

    public static void main(String[] args) {
        
        Map<String, Integer> map = new LinkedHashMap<>();
        map.put("a", 1);
        map.put("b", 0);
        map.put("c", 4);
        map.put("d", 0);
        map.put("e", 1);
        map.put("f", 1);
        
        Map<Integer, List<String>> result = map.entrySet()
                .stream()
                .collect(Collectors.groupingBy(
                        Map.Entry::getValue,
                        Collectors.mapping(Map.Entry::getKey, Collectors.toList())
                ));
        
        System.out.println(result);
    }

元投稿に合わせてメソッドにしてみる。

    public static void main(String[] args) {
        
        Map<String, Integer> map = new LinkedHashMap<>();
        map.put("a", 1);
        map.put("b", 0);
        map.put("c", 4);
        map.put("d", 0);
        map.put("e", 1);
        map.put("f", 1);
        
        Map<Integer, List<String>> result = map.entrySet()
                .stream()
                .collect(groupingBy(Map.Entry::getValue, Map.Entry::getKey));
        
        System.out.println(result); // => {0=[b, d], 1=[a, e, f], 4=[c]}
    }

    private static <T, K, V> Collector<T, ?, Map<K, List<V>>> groupingBy(
            Function<T, K> keyMapper,
            Function<T, V> valueMapper
    ) {
        return Collectors.groupingBy(
                keyMapper,
                Collectors.mapping(valueMapper, Collectors.toList())
        );
    }

どこかで見た気が...

とここまで書いて少し前に見た @komiya_atsushi さんの [Java 8][Stream API] オブジェクトの List から Map を生成する方法を模索する という投稿にあったコードに似ている気がしたので、作成したgroupingByメソッドをそちらのコードでも使ってみた。

元のコード
    static Map<String, List<String>> byGroupingByAndMapping(List<GroupUser> groupUsers) {
        return groupUsers.stream()
                .collect(Collectors.groupingBy(
                        GroupUser::groupName,
                        Collectors.mapping(
                                GroupUser::userName,
                                Collectors.toList())));
    }
今回作成したgroupingBy()メソッドを使用
    static Map<String, List<String>> byGroupingByAndMapping(List<GroupUser> groupUsers) {
        return groupUsers.stream()
                .collect(groupingBy(GroupUser::groupName, GroupUser::userName));
    }

単にショートカット的なメソッドを作って使っただけなんだけど、少しスッキリしたような気がする。
頻繁に使うようであればこういうのをユーティリティクラスに用意しておいたほうがいいかもしれない。

3
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?