- PR -

Map系でEntryをValueの値でソートするには?

投稿者投稿内容
A.K.渡邉
常連さん
会議室デビュー日: 2004/11/15
投稿数: 30
投稿日時: 2005-04-27 03:14
Keyの値の大小でソートするのではなく、Valueの値でソートしたいと思います。どのような方法がありますでしょうか?Keyはすべてuniqueであり、Valueの値には重複したものがあり、KeyとValueをひっくり返して使用できないことが条件です。

KeyとValueがStringですので以前は(Value + Key)したものをTreeSetに入れてソートし、StringTokenizerで分割して結果を得ていました。スマートな方法を模索しています。返信お願い致します。
nekoyama
ベテラン
会議室デビュー日: 2005/03/12
投稿数: 71
投稿日時: 2005-04-27 03:39
Comparatorインターフェイスを実装したクラスを作成して、java.util.Collectionsクラスのsort(List list, Comparator c) メソッドを実行してはいかがでしょうか。



かずくん
ぬし
会議室デビュー日: 2003/01/08
投稿数: 759
お住まい・勤務地: 太陽系第三惑星
投稿日時: 2005-04-27 09:19
引用:

Comparatorインターフェイスを実装したクラスを作成して、java.util.Collectionsクラスのsort(List list, Comparator c) メソッドを実行してはいかがでしょうか。



これだけだと、MapはListインターフェースをもってないのにどーすんの?
って思ってしまいます。

もし、java.util.Collections#sort(List list, Comparator c)を使用するのであれば、
 
1. Map#valuesで値のシーケンスを取り出す。
2. ArrayListのコンストラクタに値のシーケンスを渡し、Listに変換する。
3-a. java.util.Collections#sort(List list, Comparator c)でソートする。

という手順になるでしょう。

別解としては、Map.Valuesでソートした値を返すMapのサブクラスを作るという方法もあります。
A.K.渡邉
常連さん
会議室デビュー日: 2004/11/15
投稿数: 30
投稿日時: 2005-04-28 09:29
書き込みありがとうございます。多分こういうことなんだと思います。

HashMap h = new HashMap();

h.put("1", "hoge");
h.put("2", "oge");
h.put("3", "hoge");
h.put("4", "ge");
h.put("5", "e");

Collection l = h.values();
ArrayList al = new ArrayList();
al.addAll(l);
Collections.sort(al);

int i = Collections.binarySearch(al, "e");
System.out.println("position of 'e': " + i);//値は0
i = Collections.binarySearch(al, "ge");
System.out.println("position of 'ge': " + i);//値は1

言葉足らずで申し訳ないと思っていますが、最終的にはEntryをValueの値でソートし、ソートされたKeyをArrayListにするということをやってみたいのです。自分では分かったような気分になっているのですが、手持ちにJava環境がないのでまだ実証できてません。何かスマートな方法がありましたら宜しくお願いします。
シュン
ぬし
会議室デビュー日: 2004/01/06
投稿数: 328
お住まい・勤務地: 東京都
投稿日時: 2005-04-28 10:17
コード:


Map m;//ソート対象のMapインスタンス

ArrayList entries = new ArrayList(m.entrySet());
Collections.sort(entries,new Comparator(){
public int compare(Object o1, Object o2){
Map.Entry e1 =(Map.Entry)o1;
Map.Entry e2 =(Map.Entry)o2;
//e1.getValue()とe2.getValue()の戻り値の
 //大小関係をリターンしてください。
}
});



これで、entriesにはMapのvalueの値でソートされたMap.Entry
が入っていますので、イテレートしてMap.Entry#getKey()していけ
ば、望みどうりになるかと思います。

equals()のオーバーライドは不要だったので削除。



[ メッセージ編集済み 編集者: シュン 編集日時 2005-04-28 17:25 ]
A.K.渡邉
常連さん
会議室デビュー日: 2004/11/15
投稿数: 30
投稿日時: 2005-04-28 16:15
返信ありがとうございます。

ValueがStringである、という場合ならば下記のようになりますね。

HashMap m = new HashMap();
m.put("1", "hoge");
m.put("2", "oge");
m.put("3", "hoge");
m.put("4", "ge");
m.put("5", "e");

ArrayList entries = new ArrayList(m.entrySet());

Collections.sort(
entries,
new Comparator(){
public int compare(Object o1, Object o2){
Map.Entry e1 =(Map.Entry)o1;
Map.Entry e2 =(Map.Entry)o2;
String e1Value = (String) e1.getValue();
String e2Value = (String) e2.getValue();
return (e1Value.compareTo(e2Value));
}
public boolean equals(Object obj){
return super.equals(obj);
}
}
);

ArrayList keys = new ArrayList();

for(int i = 0; i < entries.size(); i ++){
Map.Entry me = (Map.Entry) entries.get(i);
keys.add((String)me.getValue());
}

ただしIteratorを使うとパフォーマンスが落ちるので、Listを使ってみました。自分が欲しいものは出来上がりましたので満足しています。書き込みありがとうございました。
想馬
大ベテラン
会議室デビュー日: 2003/05/29
投稿数: 245
お住まい・勤務地: 神奈川・東京
投稿日時: 2005-04-28 16:37
ランダムアクセスをしないで順次アクセスのみの用途なら、ArrayList#get( int index ) よりも LinkedList から
Iterator を取り出して Iterator#next() を使った方が速いですよ。
A.K.渡邉
常連さん
会議室デビュー日: 2004/11/15
投稿数: 30
投稿日時: 2005-04-28 16:53
想馬さん、返信ありがとうございます。

自分はこちらをみて発言したつもりなんですけど、何か間違っているのでしょうか?
http://www.asahi-net.or.jp/~dp8t-asm/java/articles/notes/02/article.html#id_1079_

ちなみに使用したソースはちと古いです(2000年のもの)。興味がありますので、是非勉強してみたいと思います。返信お願いします。

[ メッセージ編集済み 編集者: A.K.渡邉 編集日時 2005-04-28 16:55 ]

スキルアップ/キャリアアップ(JOB@IT)