質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Q&A

解決済

4回答

8425閲覧

【Java】CollectorsクラスのgroupingByメソッドを使用した際の出力順序について

kazu0630

総合スコア26

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

0グッド

0クリップ

投稿2020/04/24 07:06

編集2020/04/24 07:07

いつもお世話になっております。

CollectorsクラスのgroupingByメソッドの仕様について、質問をさせていただきたいです。

上記のメソッドを使用した際に、グルーピングが行われますが、その結果を出力した際の出力順序には、決まりはないのでしょうか。

groupByの対象となるListの中身

  • new Musician("Jimi Hendrix", Musician.Category.ROCK)
  • new Musician("Eric Dolphy", Musician.Category.JAZZ)
  • new Musician("J.S.Bach", Musician.Category.CLASSICAL)
  • new Musician("Charles Mingus", Musician.Category.JAZZ)

Collectorsクラス:groupingBy Javadoc

リストの中身の順番を変えた場合の出力結果をいくつか記載致します。

<出力結果>
{JAZZ=[Eric Dolphy, Charles Mingus], ROCK=[Jimi Hendrix], CLASSICAL=[J.S.Bach]}

Java

1import java.util.Arrays; 2import java.util.List; 3import java.util.Map; 4import java.util.stream.Collectors; 5 6public class Test { 7 8 public static void main(String[] args) { 9 10 List<Musician> musicList = Arrays.asList( 11        new Musician("Jimi Hendrix", Musician.Category.ROCK), 12 new Musician("Eric Dolphy", Musician.Category.JAZZ), 13 new Musician("J.S.Bach", Musician.Category.CLASSICAL), 14 new Musician("Charles Mingus", Musician.Category.JAZZ)); 15 16 17 Map<Musician.Category, List<String>> map = musicList.stream().collect(Collectors 18 .groupingBy(Musician::getCategory, Collectors.mapping(Musician::getName, Collectors.toList()))); 19 20 System.out.println(map); 21 } 22 23} 24 25

Java

1public class Musician { 2 public enum Category { 3 ROCK, JAZZ, CLASSICAL 4 } 5 6 private String name; 7 private Category category; 8 9 public Musician(String name, Category category) { 10 this.name = name; 11 this.category = category; 12 } 13 14 public String getName() { 15 return name; 16 } 17 18 public void setName(String name) { 19 this.name = name; 20 } 21 22 public Category getCategory() { 23 return category; 24 } 25 26 public void setCategory(Category category) { 27 this.category = category; 28 } 29 30}

<出力結果>
{CLASSICAL=[J.S.Bach], JAZZ=[Eric Dolphy, Charles Mingus], ROCK=[Jimi Hendrix]}

Java

1import java.util.Arrays; 2import java.util.List; 3import java.util.Map; 4import java.util.stream.Collectors; 5 6public class Test { 7 8 public static void main(String[] args) { 9 10 List<Musician> musicList = Arrays.asList( 11 new Musician("Eric Dolphy", Musician.Category.JAZZ), 12 new Musician("J.S.Bach", Musician.Category.CLASSICAL), 13 new Musician("Charles Mingus", Musician.Category.JAZZ), 14 new Musician("Jimi Hendrix", Musician.Category.ROCK)); 15 16 Map<Musician.Category, List<String>> map = musicList.stream().collect(Collectors 17 .groupingBy(Musician::getCategory, Collectors.mapping(Musician::getName, Collectors.toList()))); 18 19 System.out.println(map); 20 } 21 22}

<出力結果>
{JAZZ=[Charles Mingus, Eric Dolphy], CLASSICAL=[J.S.Bach], ROCK=[Jimi Hendrix]}

Java

1import java.util.Arrays; 2import java.util.List; 3import java.util.Map; 4import java.util.stream.Collectors; 5 6public class Test { 7 8 public static void main(String[] args) { 9 10 List<Musician> musicList = Arrays.asList( 11 new Musician("J.S.Bach", Musician.Category.CLASSICAL), 12 new Musician("Charles Mingus", Musician.Category.JAZZ), 13 new Musician("Jimi Hendrix", Musician.Category.ROCK), 14      new Musician("Eric Dolphy", Musician.Category.JAZZ)); 15 16 Map<Musician.Category, List<String>> map = musicList.stream().collect(Collectors 17 .groupingBy(Musician::getCategory, Collectors.mapping(Musician::getName, Collectors.toList()))); 18 19 System.out.println(map); 20 } 21 22} 23

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答4

0

Mapのキーの並びが気に入らないのであれば、キーでソートしてくれるインスタンスを渡せばよろしいのではないかと。

swordoneさんの指摘を反映しました。

Mapのキーの並びが気に入らないのであれば、キーの自然順序(enum定数の宣言される順序)に並べてくれるインスタンスを渡せばよろしいのではないかと。

java

1 Map<Musician.Category, List<String>> map = 2 musicList.stream().collect( 3 Collectors.groupingBy( 4 Musician::getCategory, 5 // EnumMap::new, <- こうは、書けないので訂正します 6 () -> new EnumMap<>(Musician.Category.class), 7 Collectors.mapping(Musician::getName, Collectors.toList())));

xebmeさんからのお題。

2020/04/25 00:47
グループ分けされた音楽家名もCollectors#toCollectionで並べかえてください

わたしには、荷が重すぎました。Collectors#toCollection()の例。是非ご提示いただければ。 > xebmeさん

java

1 for (int count = 0; count < 3; count++) { 2 Collections.shuffle(musicList); 3 final Map<Musician.Category, List<String>> map = musicList.stream().collect(Collectors 4 .groupingBy(Musician::getCategory, 5 () -> new EnumMap<>(Musician.Category.class), 6 Collectors.mapping(Musician::getName, Collectors.toCollection(() -> new ArrayList<>())))) 7 .entrySet().stream() 8 .collect( 9 Collectors.toMap( 10 x -> x.getKey(), 11 k -> { 12 Collections.sort(k.getValue()); 13 return k.getValue(); 14 }, 15 (a, b) -> { 16 System.out.println(" a: " + a); 17 System.out.println(" b: " + b); 18 a.addAll(b); 19 Collections.sort(a); 20 return a; 21 }, 22 () -> new EnumMap<>(Musician.Category.class))); 23 24 System.out.println(String.format("(%s) (%s) : %s", count, map.getClass().getSimpleName(), map)); 25 }

こっちだと、みじかく書けるのですが (^^;

kotlin

1 repeat(3) { count -> 2 val map = 3 musicList.shuffled() 4 .groupBy { it.category } 5 .map { entry -> entry.key to entry.value.map { it.name }.sorted() } 6 .toMap(EnumMap(Musician.Category::class.java)) 7 println("(%s) (%s) : %s".format(count, map.javaClass.simpleName, map)) 8 }

投稿2020/04/24 07:40

編集2020/04/25 00:16
shiketa

総合スコア4061

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

swordone

2020/04/24 07:44

Enumがキーなので、EnumMapのほうが適しているかと思います。
shiketa

2020/04/24 12:26

EnumMapの存在は気づいていませんでした。指摘ありがとうございました。ひとつ道具が増えました。
xebme

2020/04/24 15:47

グループ分けされた音楽家名もCollectors#toCollectionで並べかえてください。
shiketa

2020/04/24 22:40

やはりそう来ますよね。わたしには、荷が重すぎました。Collectors#toCollection()の例。是非ご提示いただければ m(._.)m
guest

0

ベストアンサー

JavaDocに書いてあるように、

返されるMapの型、可変性、直列化可能性、またはスレッド安全性は一切保証されません。

Java標準で用意してあるMapでも、実装の中に順序が保証されないものがあるわけですし、「順番についても何も保証されない」と考えるのがいちばん安全です。

投稿2020/04/24 07:18

maisumakun

総合スコア146018

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

kazu0630

2020/04/25 06:53 編集

皆様、ご回答いただき、ありがとうございました。 いろいろとコメントのやり取りを拝見し、勉強させていただきました。 また、機会がありましたら、ご回答いただけますと幸いです。 この度はありがとうございました。
guest

0

CollectorsクラスのgroupingByメソッドの仕様について、質問をさせていただきたいです。
上記のメソッドを使用した際に、グルーピングが行われますが、その結果を出力した際の出力順序には、決まりはないのでしょうか。

# はなしがずれてきてしまった感があるので、ここに対して。

件のメソッドの実装はこう。

java

1public final class Collectors { 2 ... 3 public static <T, K, A, D> 4 Collector<T, ?, Map<K, D>> groupingBy(Function<? super T, ? extends K> classifier, 5 Collector<? super T, A, D> downstream) { 6 return groupingBy(classifier, HashMap::new, downstream); 7 }

返さえるMapの実装は、HashMap。

曰く。

Mapインタフェースのハッシュ表に基づく実装です。...このクラスはマップの順序を保証しません。特に、その順序を常に一定に保つことを保証しません。

「順序を保証し」ないそうです。さらに「順序を常に一定に保つことを保証しません」との由。

投稿2020/04/25 00:26

shiketa

総合スコア4061

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

xebme

2020/04/25 02:00

質問の意図は何か。 ・デフォルト実装を使うなら順序を保証しない。 ・自分でSupplierを指定するなら順序性を持たせることができる。 ということですね。前者を意図するのであれば後者は答える必要がない。
shiketa

2020/04/25 02:16

わたしが TreeMap::new を持ち出したので、はなしがずれてしまった... (^^;
guest

0

コレクションの並び順

コレクションの要素の並び順を決定するのはComparatorです。この問題は、格納するコレクションを生成する際、どの並び順のComparatorを指定するかを考えることです。

Map<Musician.Category, Set<String>>

並び順を管理しやすいように、カテゴリ用のMapに順序を指定できるTreeMapを、音楽家用のSetに重複を排除し順序を指定できるTreeSetを使用します。Collectors.groupnigByに指定するSupplierをそれぞれ以下のように定義。

カテゴリ別、音楽家のリスト、カテゴリの整列順

Java

1// カテゴリ別マップのSupplier 2() -> new TreeMap<>(カテゴリ用のComparator) 3 4// カテゴリ名順 5Comparator.<Musician.Category, String>comparing(c -> c.name()); 6// カテゴリの定義順 7Comparator.<Musician.Category, Integer>comparing(c -> c.ordinal()); 8// カテゴリの自然順(定義順) 9Comparator.<Musician.Category>naturalOrder(); 10// カテゴリの自然逆順(定義逆順) 11Comparator.<Musician.Category>reverseOrder();

音楽家のセット(重複排除)の整列順

Java

1// 音楽家セットのSupplier 2() -> new TreeSet<>(音楽家用のComparator) 3 4// 音楽家の自然順 5Comparator.<String>naturalOrder(); 6// 音楽家の自然逆順 7Comparator.<String>reverseOrder();

Collectors.groupnigByにSupplierの設定

カテゴリ用のComparator、音楽家用のComparator、をそれぞれ適用します。

Java

1musicianList -> 2 musicianList.stream() 3 .collect( 4 Collectors.groupingBy( 5 Musician::getCategory, 6 () -> new TreeMap<>(カテゴリ用のComparator), 7 Collectors.mapping( 8 Musician::getName, 9 Collectors.toCollection(() -> new TreeSet<>(音楽家用のComparator)))));

テスト用コード

Java

1import java.util.Arrays; 2import java.util.Comparator; 3import java.util.List; 4import java.util.Map; 5import java.util.Set; 6import java.util.TreeMap; 7import java.util.TreeSet; 8import java.util.function.BiFunction; 9import java.util.function.Function; 10import java.util.stream.Collectors; 11 12public class MusicianTest_ { 13 14 static Comparator<Musician.Category> categoryNameOrder = Comparator.<Musician.Category, String>comparing(c -> c.name()); 15 static Comparator<Musician.Category> categoryOrder = Comparator.<Musician.Category, Integer>comparing(c -> c.ordinal()); 16 static Comparator<Musician.Category> categoryNaturalOrder = Comparator.<Musician.Category>naturalOrder(); 17 static Comparator<Musician.Category> categoryReverseOrder = Comparator.<Musician.Category>reverseOrder(); 18 19 static Comparator<String> musicianNaturalOrder = Comparator.naturalOrder(); 20 static Comparator<String> musicianReverseOrder = Comparator.reverseOrder(); 21 22 static BiFunction<Comparator<Musician.Category>, Comparator<String>, Function<List<Musician>, Map<Musician.Category, Set<String>>>> supplyFunc = 23 (categoryComparator, musicianComparator) -> 24 musicianList -> 25 musicianList.stream() 26 .collect( 27 Collectors.groupingBy( 28 Musician::getCategory, 29 () -> new TreeMap<>(categoryComparator), 30 Collectors.mapping( 31 Musician::getName, 32 Collectors.toCollection(() -> new TreeSet<>(musicianComparator))))); 33 34 public static void main(String[] args) { 35 36 List<Musician> musicianList = Arrays.asList( 37 new Musician("Jimi Hendrix", Musician.Category.ROCK), 38 new Musician("Jeff Beck", Musician.Category.ROCK), 39 new Musician("Eric Dolphy", Musician.Category.JAZZ), 40 new Musician("Johann Sebastian Bach", Musician.Category.CLASSICAL), 41 new Musician("Josquin Des Prez", Musician.Category.CLASSICAL), 42 new Musician("François Couperin", Musician.Category.CLASSICAL), 43 new Musician("Charles Mingus", Musician.Category.JAZZ), 44 new Musician("Art Tatum", Musician.Category.JAZZ)); 45 46 Map<Musician.Category, Set<String>> map = null; 47 System.out.print("カテゴリ名順、音楽家名昇順 : "); 48 map = (supplyFunc.apply(categoryNameOrder, musicianNaturalOrder)).apply(musicianList); 49 System.out.println(map); 50 System.out.print("カテゴリ名順、音楽家名降順 : "); 51 map = (supplyFunc.apply(categoryNameOrder, musicianReverseOrder)).apply(musicianList); 52 System.out.println(map); 53 System.out.print("カテゴリ順、音楽家名昇順 : "); 54 map = (supplyFunc.apply(categoryOrder, musicianNaturalOrder)).apply(musicianList); 55 System.out.println(map); 56 System.out.print("カテゴリ順、音楽家名降順 : "); 57 map = (supplyFunc.apply(categoryOrder, musicianReverseOrder)).apply(musicianList); 58 System.out.println(map); 59 60 } 61 62}

投稿2020/04/25 00:17

xebme

総合スコア1090

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

shiketa

2020/04/25 00:36 編集

ありがとうございます。 nameの重複を勝手に排除してはいけないと判断していたので、TreeSetは避けていましたった。
xebme

2020/04/25 02:05

質問の読み間違いでした。 groupingByのデフォルト実装の結果は総称的なMapである。したがって順序は保証されない。(当然) (しかしサプライヤーを指定することで順序性を持つMapに格納することもできる)
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問