Key と Value を入れ替えた Map を取得する方法 : Java と JavaScript 編
Key と Value を入れ替えた Map (連想配列) を作る方法を調べた。
Java も JavaScript も、PHP でいうところの array_flip()
みたいな標準メソッドは存在しなかったので、簡単なやり方を説明する。
- 参考 :
array_flip
関数 : 配列のキーと値を入れ替える | 今日のPHP関数 - PHP のarray_flip()
について。
TL; DR
- Java : Commons-Collections with Generics …
BidiMap#inverseBidiMap()
- JavaScript : Underscore.js …
_.invert()
Java : BidiMap が一番楽
Apache Commons の中の Commons-Collection というライブラリが、コレクションの便利メソッドをたくさん持っている。しかし本家のライブラリはジェネリクスに対応していないので、フォークしてジェネリクスに対応した Commons-Collections with Generics を使ってみる。
以下から collections-generic-4.01.zip
をダウンロードし、collections-generic-4.01.jar
を Jar ライブラリとして導入する。
そしたら以下のように使う。
// 普通にマップを作る
Map<String, Integer> map = new HashMap<String, Integer>();
map.put("にんじん", 150);
map.put("レタス" , 200);
map.put("キャベツ", 500);
map.put("キャベツ", 200);
// key が衝突した時は後勝ちになるので、"キャベツ" の value は 200 になる
// BidiMap : Bidirectional Map (双方向マップ) を使い、変数 map を変換する
BidiMap<String, Integer> bidiMap = new DualHashBidiMap<String, Integer>(map);
bidiMap.getKey(200); // "キャベツ"
bidiMap.get("レタス"); // null
bidiMap.get("キャベツ"); // 200
// #getKey() というメソッドで、value から key を取得できるようになる
// その代わり、重複する value は key と同じように後勝ちになるため、
// 先に宣言された key "レタス" は削除され、同じ value 200 を持つ key "キャベツ" だけが格納されている
// BidiMap#inverseBidiMap() を使うと、key と value を入れ替えた BidiMap が生成できる
BidiMap<Integer, String> flipMap = bidiMap.inverseBidiMap();
flipMap.get(200); // "キャベツ"
flipMap.getKey("レタス"); // null
flipMap.getKey("キャベツ"); // 200
// 先程、変数 bidiMap を操作した時と、#get() と #getKey() が逆になっている = key と value が入れ替わっている
BidiMap っていうのに普通の Map を取り込むと、双方向マップ、つまり Key と Value が1対1であることを保証する Map が出来上がる。Key と Value を入れ替えた Map に変換するには、Value 側にも重複があってはいけないわけだ。
BidiMap 自体は普通に Map として使えるので、コンストラクタに引数を渡さず、新規で作っても良い。この場合の BidiMap#put() は、value の重複を検知して後勝ちするように自動的に管理してくれる。
BidiMap<String, Integer> bidiMap = new DualHashBidiMap<String, Integer>();
bidiMap.put("にんじん", 150);
bidiMap.put("ほうれんそう", 150);
bidiMap.get("にんじん"); // null
bidiMap.getKey(150); // "ほうれんそう"
// "にんじん" は、後に put された "ほうれんそう" と同じ value を持っていたので、Map から remove されていた。
- 参考 : Apache commonsが便利な件(commons-collections編-1) - 都元ダイスケ IT-PRESS
- 参考 : Mapのvalueからkeyの値を取得したい | あっきーブログ
JavaScript : Underscore.js が便利
以下のページに、Legacy JavaScript、ES5、jQuery での実装方法が載っている。
Legacy JavaScript だと以下の記事のコードが分かりやすかったので、整形しつつ転載。
/**
* example: arrayFlip( { a: 1, b: 1, c: 2 } )
* returns: { 1: "b", 2: "c" }
*/
function arrayFlip(trans) {
var key;
var tmpArr = {};
for(key in trans) {
if(trans.hasOwnProperty(key)) {
tmpArr[trans[key]] = key;
}
}
return tmpArr;
}
だが、一番手っ取り早いのは、便利メソッドが沢山つまったライブラリ、Underscore.js を導入することだろう。
上の公式サイトから underscore.js もしくは underscore-min.js (圧縮版) をダウンロードして script 要素で読み込むようにしたり、npm でインストールして require したりしても OK。
そうすると、以下のような関数が使えるようになる。
// 連想配列を用意
var trans = { A: "aaa", B: "bbb", C: "ccc" };
// Underscore.js の _.invert() メソッドで key と value を入れ替えた連想配列を取得する
var result = _.invert(trans);
// result : { aaa: "A", bbb: "B", ccc: "C" };