0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Map の filter, sort の実装

0
Last updated at Posted at 2018-08-20

Map のフィルター

JavaScript の Array には filter メソッドがあって便利だが、Map にはその機能がないので、あると便利だな、、と思って実装してみた。
(コメントいただいたのですが、こちらで標準化がすすめられているようなので、そのうちMapの標準機能として実装されるかもしれません。)

Map のプロトタイプに filter() メソッドをぶち込んで Map そのものを拡張してしまうのはあまりに危険なので、MapUtility というクラスを定義し、そのクラスのクラスメソッドとして実装しました。

export default class MapUtility {

    /**
     * Map を key でフィルターする
     * @param {Map} map
     * @param {function} func
     * @return {Map<any, any>}
     */
    static filterByKey(map, func) {
        const newMap = new Map();
        map.forEach((value, key, map) => {
            if (func(key)) {
                newMap.set(key, value);
            }
        });
        return newMap;
    }
}

実行例としては以下のような感じ。

const testMap = new Map([
    ['芥川', 123],
    ['川端', 456],
    ['夏目', 789],
    ['町田', 1000],
    ['三島', 10001],
]);

const filteredMap = MapUtility.filterByKey(testMap, key => {
    return (key !== '川端');
});

console.log(filteredMap);
//Map { '芥川' => 123, '夏目' => 789, '町田' => 1000, '三島' => 10001 }

きちんと川端さんが除外されています。

また上記では key でフィルターしていますが、もっと汎用性を高めたかったら以下のようにすればよいです。

class MapUtility {

    /**
     * Map をフィルターする
     * @param {Map} map
     * @param {function} func
     * @return {Map<any, any>}
     */
    static filterByKey(map, func) {
        const newMap = new Map();
        map.forEach((value, key, map) => {
            if (func(value, key, map)) {
                newMap.set(key, value);
            }
        });
        return newMap;
    }
}

呼び出し側では

const filteredMap = MapUtility.filterByKey(testMap, (value, key, map) => {
    //...フィルター条件をここに書く
});

Map をキーでソート

ついでにソートもできたら便利だな、と思いましたがfilterのときほどスマートにはできなかったのがちょっと残念。どなたかもっとスマートなやり方あるよって方コメントください。

export default class MapUtility {

    /**
     * Map を key でソートする
     * @param map
     * @param func
     * @return {Map<any, any>}
     */
    static sortByKey(map, func) {
        const newMap = new Map();
        const keysArray = Array.from(map.keys());
        const sortedKeys = keysArray.sort(func);
        for (const key of sortedKeys) {
            newMap.set(key, map.get(key));
        }
        return newMap;
    }
}

呼び出し側では

const testMap = new Map([
    ['c', 123],
    ['a', 456],
    ['d', 789],
    ['b', 1000],
    ['e', 10001],
]);

// 昇順ソート
const sortedMap = MapUtility.sortByKey(testMap, (a, b) => {
    if(a < b){
        return -1;
    }else if(a > b){
        return 1;
    }
    return 0;
});

console.log(sortedMap);
//Map { 'a' => 456, 'b' => 1000, 'c' => 123, 'd' => 789, 'e' => 10001 } 

// for of, forEach どちらでもアルファベット順に出力される
// ソートする前は記述した順番にループしてしまう
for (const [key, value] of sortedMap) {
    console.log(`key:${key}, value:${value}`);
}

sortedMap.forEach((value, key, map) => {
    console.log(`key:${key}, value:${value}`);
});

ループもきちんとキーをアルファベット順になります。

なお Array.sort()は要素の文字をUnicodeに変換し、その数値でソートしますので、上記のようにキーの先頭がすべて小文字アルファベットの場合、すべて大文字アルファベットの場合、すべて数字,すべてひらがな、すべてカタカナの場合はうまくソートできますが、これらが混在していたり、漢字が混ざっていたりするとちょっとややこしくなります。

こちらの記事に結構詳しく書いてありました。参考までに。
https://goma.pw/article/2015-11-18-0/

0
1
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?