web-dev-qa-db-ja.com

JavaScriptでセットをマップ/削減/フィルターする方法は?

JavaScriptでmap/reduce/filter/etc a Setにする方法はありますか、それとも自分で記述する必要がありますか?

賢明なSet.prototype拡張機能を次に示します

Set.prototype.map = function map(f) {
  var newSet = new Set();
  for (var v of this.values()) newSet.add(f(v));
  return newSet;
};

Set.prototype.reduce = function(f,initial) {
  var result = initial;
  for (var v of this) result = f(result, v);
  return result;
};

Set.prototype.filter = function filter(f) {
  var newSet = new Set();
  for (var v of this) if(f(v)) newSet.add(v);
  return newSet;
};

Set.prototype.every = function every(f) {
  for (var v of this) if (!f(v)) return false;
  return true;
};

Set.prototype.some = function some(f) {
  for (var v of this) if (f(v)) return true;
  return false;
};

少し設定してみましょう

let s = new Set([1,2,3,4]);

そして、いくつかの愚かな小さな機能

const times10 = x => x * 10;
const add = (x,y) => x + y;
const even = x => x % 2 === 0;

そして、彼らがどのように機能するかを見てください

s.map(times10);    //=> Set {10,20,30,40}
s.reduce(add, 0);  //=> 10
s.filter(even);    //=> Set {2,4}
s.every(even);     //=> false
s.some(even);      //=> true

いいじゃない?ええ、私もそう思います。それをいイテレータの使用と比較してください

// puke
let newSet = new Set();
for (let v in s) {
  newSet.add(times10(v));
}

そして

// barf
let sum = 0;
for (let v in s) {
  sum = sum + v;
}

JavaScriptでmapを使用してreduceおよびSetを実現するより良い方法はありますか?

87
user633183

簡単な方法は、ES6スプレッド演算子を使用して配列に変換することです。

その後、すべての配列関数が使用可能になります。

const mySet = new Set([1,2,3,4]);
[...mySet].reduce()
69
ZephDavies

コメントからの議論を要約すると:notに設定する技術的な理由はありませんが、reduceがありますが、現在提供されていないため、 ES7で変更されることを願っています。

mapに関しては、それを単独で呼び出すとSet制約に違反する可能性があるため、その存在は議論の余地があるかもしれません。

関数(a) => 42を使用したマッピングを検討してください。セットのサイズが1に変更されますが、これはまたはそうでないかもしれません。

あなたがそれを違反しても大丈夫なら、例えばとにかく折りたたむので、mapに渡す直前にすべての要素にreduce部分を適用して、中間コレクション(これはSetではないこの点)削減される予定の要素が重複している可能性があります。これは、処理を行うために配列に変換することと本質的に同等です。

20

map/reduce/filterコレクションのMap/Setが不足している原因は、主に概念的な問題のようです。 JavaScriptの各コレクションタイプは、実際にこれを許可するためだけに独自の反復メソッドを指定する必要があります

const mySet = new Set([1,2,3]);
const myMap = new Map([[1,1],[2,2],[3,3]]);

mySet.map(x => x + 1);
myMap.map(([k, x]) => [k, x + 1]);

の代わりに

new Set(Array.from(mySet.values(), x => x + 1));
new Map(Array.from(myMap.entries(), ([k, x]) => [k, x + 1]));

代替手段は、entries/values/keysIteratorsを返すため、map/reduce/filterをiterable/iteratorプロトコルの一部として指定することでした。ただし、すべての反復可能要素が「マッピング可能」ではないことも考えられます。別の選択肢は、このまさに目的のために別個の「収集プロトコル」を指定することでした。

しかし、ESでのこのトピックに関する現在の議論は知りません。

7
user6445533