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


131

JavaScriptでmap/ reduce/ filter/ etcを作成する方法はあり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ますか?


map-reduce-ing aの問題Setは、セットがファンクタではないことです。
Bartek Banachewicz 2015年

@BartekBanachewiczええ、それは一種の問題です...そうですか?
ありがとう

2
さて、考慮してくださいvar s = new Set([1,2,3,4]); s.map((a) => 42);。要素の数を変更しますが、map通常はそうすることは想定されていません。保持されたオブジェクトの一部のみを比較している場合はさらに悪いことになります。技術的には、どのオブジェクトを取得するかは不定だからです。
Bartek Banachewicz 2015年

私はそれを検討しましたが、私が(個人的に)それを無効と見なすかどうかはわかりません。わかりましたので、少なくともforEachそのシナリオには存在しますが、なぜreduceそれができないのですか?
ありがとう

回答:


105

これを簡単に行うには、ES6スプレッド演算子を使用して配列に変換します。

その後、すべての配列関数を使用できます。

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

1
セットには機能がありませんので!これは、このトピックにはまだ記載されていない、完全なガイド付きの理解された回避策です。「時間がかかる」という事実は、Setがこれらの機能を実装するまでの回避策を支払うのは悲しい代償です!
ZephDavies 2017年

1
これとArray.fromの違いは何ですか
pete

9
少なくとも私にとって、これとの違いArray.fromArray.fromTypeScript で動作することです。使用すると[...mySet]エラーになります:TS2461: Type 'Set<number>' is not an array type.
Mikalマドセン

1
スプレッドとArray.from()については、stackoverflow.com / a / 40549565/5516454を参照してください 。基本的に、どちらもここで使用できます。Array.from()は、@@iteratorメソッドを実装しない配列のようなオブジェクトをさらに実行できます。
ZephDavies

typescriptではまだ動作しません。私が取得ERROR TypeError: this.sausages.slice is not a function
Simon_Weaver

22

コメントからの議論を要約すると、「を持たない」に設定する技術的な理由はありませんreduce、現在は提供されていません。ES7で変更されることを期待できます。

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

関数を使用したマッピングを検討してください。(a) => 42これにより、セットのサイズが1に変更されます。これは必要な場合とそうでない場合があります。

あなたはとにかくフォールドするつもり例えばので、あなたが適用できることを違反としている[OK]次の場合mapだけに渡す前にすべての要素の一部をreduce受け入れてこのように、その中間(コレクションこの時点では設定されていない)のこと削減される要素が重複している可能性があります。これは基本的に、処理を行うために配列に変換することと同じです。


1
これは、(上記のコードを使用)を除いて、ほとんどが良好であるs.map(a => 42)ことになるSet { 42 }要素の「重複」マッピングされた結果は、異なる長さになるように、そこではありません。多分表現を更新し、私はこの答えを受け入れます。
ありがとう

@naomikああderp私はそれを書いているとき、最初のコーヒーを終えたところだった。2番目の外観では、reduceに渡された中間コレクションは、それがセットではないことを受け入れると、すぐに要素が含まれる可能性があります。
Bartek Banachewicz 2015年

わかりました。マップは同じタイプにマップする必要があるため、宛先セットで衝突が発生する可能性があります。この質問を見つけたとき、私はマップがセットの配列にマップすると考えていました。()(あなたはset.toArrayをしたかのようにマップ() `。
Simon_Weaver

2
ScalaとHaskellでは、セットはマップ操作をサポートしています-セット内の要素の数を減らすことができます。
Velizar Hristov

8

map/ reduce/ filteron 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/はsをkeys返すため、反復可能/反復子プロトコルの一部としてmap / reduce / filterを指定することでしたIterator。すべての反復可能オブジェクトが「マップ可能」であるとは限らないことも考えられます。別の方法としては、まさにこの目的のために別の「収集プロトコル」を指定することでした。

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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.