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

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

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

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

Q&A

解決済

4回答

4523閲覧

Map<String, List>をバリューで昇順にソートしたい

snooooopy_16

総合スコア15

Java

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

0グッド

0クリップ

投稿2018/03/13 10:09

下記のような<String, List>の型を持つmapの中身をList型のバリューで昇順にソートをしたいですが,実装方法が分かりません。
※バリューのList[0]の値で昇順にしたいです。
HashMap<String, List> map = new HashMap<String, List>();
map.put(key, listOTbject);※loopで下記に示すような4つのデータをmapに詰め込む処理あり

--現在のmapのデータ格納イメージ
<1,[30,aaa]>
<2,[60,abc]>
<3,[40,abc]>
<4,[70,abc]>

--理想のmapのデータ格納イメージ
<1,[30,aaa]>
<3,[40,abc]>
<2,[60,abc]>
<4,[70,abc]>
※バリューのList[0]でソートされている状態

格納時にソートする方法,もしくは格納後に並び替えを行う方法があればご教示いただければ幸いです。

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

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

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

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

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

guest

回答4

0

ベストアンサー

まず、Map自体には順序を持つ機能はありません(SortedMapなどもありますが、キーによる順序付けなので割愛します)。
値によるソートを行いたい場合、順序を保持するためのリスト等を別途用意する必要があります。
キーと値の一覧はMap.entrySetメソッドを呼び出すことで取得できます。

ソート処理は独自のルールを設定する必要があるため、java.util.Comparatorインターフェースの実装が必要です(下記ソースのValueListComparatorを参考にしてください)。
Comparatorを実装したら、Collections.sortを使用することで、ソートを行えます。

java

1import java.util.*; 2public class Test{ 3 public static void main(String[] args){ 4 HashMap<String, List> map = new HashMap<>(); 5 map.put("1",Arrays.asList(30,"aaa")); 6 map.put("2",Arrays.asList(60,"abc")); 7 map.put("3",Arrays.asList(40,"abc")); 8 map.put("4",Arrays.asList(70,"abc")); 9 10 // 順序を保持するためのリスト(Map.entrySetでキーと値の一覧が取得できます) 11 List<Map.Entry<String,List>> mapOrderList = new ArrayList<>(map.entrySet()); 12 13 // ソートの方法を指定してソート実施 14 Collections.sort(mapOrderList, new ValueListComparator()); 15 16 // ソートの結果を出力 17 for(int i=0; i<mapOrderList.size(); ++i){ 18 Map.Entry<String, List> entry= mapOrderList.get(i); 19 System.out.println( 20 i + "番目:" + 21 "<" + entry.getKey() + ", " + entry.getValue() + ">"); 22 } 23 } 24 25 // ソートの方法を決める処理 26 private static class ValueListComparator 27 implements Comparator<Map.Entry<String, List>>{ 28 29 public int compare(Map.Entry<String, List> object1, 30 Map.Entry<String, List> object2){ 31 32 // マップの値 33 List object1List = object1.getValue(); 34 List object2List = object2.getValue(); 35 36 // リストの1番目 37 Comparable object1ListFirst = (Comparable)object1List.get(0); 38 Comparable object2ListFirst = (Comparable)object2List.get(0); 39 40 return object1ListFirst.compareTo(object2ListFirst); 41 } 42 } 43}

実行結果

0番目:<1, [30, aaa]> 1番目:<3, [40, abc]> 2番目:<2, [60, abc]> 3番目:<4, [70, abc]>

投稿2018/03/13 11:35

whistyun

総合スコア149

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

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

snooooopy_16

2018/03/14 08:17

とても分かりやすくありがとうございます! ただ下記データ状態の場合, <1, [80,(1,2,3)]> <2, [40,(2,3,4)]> <3, [80,(1,2,3,4.5)]> <4, [120,(1,2)]> ソースを実行したところ,下記の通りとなりました。 <4, [120,(1,2)]> <2, [40,(2,3,4)]> <1, [80,(1,2,3)]> <3, [80,(1,2,3,4.5)]> どこか抜け穴があるのでしょうか。。
swordone

2018/03/14 08:24

Listの最初の要素、Stringになってませんか?
snooooopy_16

2018/03/14 08:33 編集

Stringで持つべきということでしょうか。 今はObject型です。
swordone

2018/03/14 08:33

Stringだと辞書順で比較するため、先頭の文字から順番を判断します。 40の「4」より120の「1」のほうが早いという理屈です。
snooooopy_16

2018/03/14 08:37

すみません,String型でした。なるほどです。修正してみます。
guest

0

Mapには「順序はない」と考えるのが普通です。ただし例外的にjava.util.LinkedHashMapというクラスがありキーを挿入した順番でエントリー(キーや値)の列挙が可能です。これは主としてLRUキャッシュ目的で使うものという印象で、自分はLRUキャッシュ以外で使ったことがありませんが、構築後に一切内容を変更しないなら、これを使えばご質問のようなMapが作れます。(一旦作った後にソートしなおすなら作り直しになります。あくまでキーの登録順に並びますので)

ただしLinkedHashMapもあくまでMapであってListではありませんので「i番目の値」なんてアクセス(ランダムアクセス)はできません。

自分にはなんでMapをソートしなきゃいけないのかがよくわかりません。Mapってのは「任意のキーによって値を取り出す連想配列」です。値の順番に内部を並び替えると何かの処理にとって都合がよくなるのかも知れませんが・・・一つのもの(Map => 連想配列)にそれとは違う別の機能(順番付きの列)を期待するのはあまり筋が良いことではない気がします。

ある順番に取り出したいのなら、別途Map.Entryを順序付きの列(List)に取り出し、それを望む順にソートすればいいのではないかという気がします。MapはMap目的で使い、順序の意識は順序付きのコレクション(List)に任せた方がわかりやすいんじゃないでしょうか。

投稿2018/03/13 11:36

編集2018/03/14 03:22
KSwordOfHaste

総合スコア18394

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

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

KSwordOfHaste

2018/03/13 13:28

なるほど、これだとMapでありListでもあるものとして扱えるということですね。 まぁしかし自分は標準ライブラリー前提で回答してみてます。標準ライブラリーについていえば少々寂しい感じのもの(java.util.Streamやjava.util.Optionalなど)もあるのでそういうものについていは他のライブラリーや他の言語がうらやましくなるのですが、普通のコレクションではそうまで凝ったことをしようとは考えたことがないですw;
guest

0

みなさんの回答にもありますが、基本的にMapに順序という考え方はありません。
Mapへの突っ込み順を保持するLinkedHashMapで作り直せば可能ではありますが、
作ったLinkedHashMapに新たにputしてしまうと、並び替えた順序は破綻します。

Java

1Map<String, List<?>> newMap = map.entrySet().stream() 2 .sorted(Comparator.comparing(entry -> (Integer) ((Entry<String, List<?>>) entry).getValue().get(0))) 3 .collect(Collectors.toMap(Entry::getKey, Entry::getValue, (l1, l2) -> l2, LinkedHashMap::new));

投稿2018/03/14 01:51

編集2018/03/14 01:55
root_jp

総合スコア4666

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

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

snooooopy_16

2018/03/14 08:17 編集

コメント先間違っていました。申し訳ございません。
guest

0

https://docs.oracle.com/javase/jp/8/docs/api/java/util/Comparator.html

このインタフェースを継承して好きなように実装してください

投稿2018/03/13 10:27

退会済みユーザー

退会済みユーザー

総合スコア0

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問