JavaScript - Mapソート(キーまたはvalueでソート)

Mapは、キー値の形で要素を格納するデータ構造です。 Mapのkeyまたはvalueに基づいてソートする方法を紹介します。

1. Spread 演算子と sort() を使用して Map を並べ替える

Spread operator を使った [...mapObject] のような表現は、key-value の要素が配列に格納された形で返されます。

配列オブジェクトに対して sort() を実行すると、キーを基準に配列がソートされます。

let myMap = new Map([
  ['c', 2],
  ['a', 4],
  ['d', 1],
  ['b', 3],
]);

let elementsArray = [...myMap];
console.log(elementsArray);

let sortedAscArray = [...myMap].sort();
console.log(sortedAscArray);

Output:

[ [ 'c', 2 ], [ 'a', 4 ], [ 'd', 1 ], [ 'b', 3 ] ]
[ [ 'a', 4 ], [ 'b', 3 ], [ 'c', 2 ], [ 'd', 1 ] ]

ソートした配列を再びMapに変換したい場合は、以下のようにMapのコンストラクタの引数でソートされた結果を渡すだけです。

let sortedAsc = new Map([...myMap].sort());

2. key を基準に昇順、降順のソート

sort() はデフォルトで key を昇順にソートします。降順でソートしたい場合は、昇順でソートされた結果を reverse() 関数で逆順に変更すると降順ソートになります。

let myMap = new Map([
  ['c', 2],
  ['a', 4],
  ['d', 1],
  ['b', 3],
]);

// Ascending
let sortedAsc = new Map([...myMap].sort());
console.log(sortedAsc);

// Decending
let sortedDsc = new Map([...myMap].sort().reverse());
console.log(sortedDsc);

Output:

Map(4) { 'a' => 4, 'b' => 3, 'c' => 2, 'd' => 1 }
Map(4) { 'd' => 1, 'c' => 2, 'b' => 3, 'a' => 4 }

2. valueを基準に昇順、降順のソート(valueがNumberのとき)

デフォルトでは、 sort() は Map のキーをソートします。

valueでソートしたい場合は、 sort((a, b) => a[1] - b[1])) のように引数で value のサイズを比較する comparator 関数を渡す必要があります。 ちなみに、 a[1]のようにIndex 1はvalue値を意味し、Index 0はkey値を意味します。

サイズを比較するときに a[1] - b[1] のように - 演算子を使用しましたが、 value が Number のときにこれでサイズを比較できます。もし文字列であれば別の方法で比較する必要がありますが、以下でもう一度説明します。

let myMap = new Map([
  ['c', 2],
  ['a', 4],
  ['d', 1],
  ['b', 3],
]);

// Ascending
let sortedByValueAsc = new Map([...myMap].sort((a, b) => a[1] - b[1]));
console.log(sortedByValueAsc);

// Decending
let sortedByValueDsc = new Map([...myMap].sort((a, b) => a[1] - b[1]).reverse());
console.log(sortedByValueDsc);

Output:

Map(4) { 'd' => 1, 'c' => 2, 'b' => 3, 'a' => 4 }
Map(4) { 'a' => 4, 'b' => 3, 'c' => 2, 'd' => 1 }

3. valueを基準に昇順、降順のソート(valueがStringのとき)

以下の例のように、valueが文字列型の場合、 (a, b) => a[1] - b[1]) のような表現でソートするとソートできません。 文字列を比較するとき、 -でサイズ比較ができないからだと思います。

a.localeCompare(b) で文字列のサイズを比較するように実装すればよい。

let myMap = new Map([
  [2, 'c'],
  [4, 'a'],
  [1, 'd'],
  [3, 'b'],
]);

// Ascending
let sortedByValueAsc = new Map([...myMap].sort((a, b) => a[1].localeCompare(b[1])));
console.log(sortedByValueAsc);

// Decending
let sortedByValueDsc = new Map([...myMap].sort((a, b) => a[1].localeCompare(b[1])).reverse());
console.log(sortedByValueDsc);

Output:

Map(4) { 4 => 'a', 3 => 'b', 2 => 'c', 1 => 'd' }
Map(4) { 1 => 'd', 2 => 'c', 3 => 'b', 4 => 'a' }

ちなみに、降順に並べ替えるとき、 reverse() で昇順の並べ替えを逆順に変える代わりに、以下のように Arrow function の比較演算を変更して降順にすぐに並べ替えるように実装することもできます。

// Decending
// let sortedByValueDsc = new Map([...myMap].sort((a, b) => a[1].localeCompare(b[1])).reverse());
let sortedByValueDsc = new Map([...myMap].sort((a, b) => b[1].localeCompare(a[1])));
codechachaCopyright ©2019 codechacha