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/