JavaScriptでセットを作成する方法は?


83

Eloquent JavaScriptの第4章では、オブジェクトを作成し、値をプロパティ名として格納し、任意の値(trueなど)をプロパティ値として割り当てることによって、値のセットが作成されます。値がすでにセットに含まれているかどうかを確認するには、in演算子を使用します。

var set = {};

if (!'Tom' in set) { 
  set.Tom = true;
}

これは慣用的なJavaScriptですか?配列をさらにうまく使用しませんか?

var set = [];

if (!'Tom' in set) { 
  set.push = 'Tom';
}

1
'Tom' in settrueの配列がどのように見えると思いますか?あなたが何かについて間違った仮定をしているように見えます、そして私は何について調べようとしています。

10
参考までに、あなたは親が必要です:if(!('Tom' in set))。現在それはfalse in set以来を意味し!'Tom' === falseます。
pimvdb 2011

ES6にはセットがあります。以下のジョンの回答を参照してください
Ben Taliadoros 2016年

回答:


101

セットはES2015(別名ES6、つまりECMAScript 6)で利用できるようになりました。ES6は、2015年6月からJavaScriptの現在の標準となっています。

ECMAScript 6には、任意の値に対して機能し、高速でNaNを正しく処理するデータ構造Setがあります。-アクセルRauschmayerES6を探ります

AxelRauschmayerの著書ExploringES6最初の2つの例:

単一要素の管理:

> let set = new Set();
> set.add('red')

> set.has('red')
true
> set.delete('red')
true
> set.has('red')
false

セットのサイズを決定してクリアする:

> let set = new Set();
> set.add('red')
> set.add('green')

> set.size
2
> set.clear();
> set.size
0

JavaScriptのセットについて詳しく知りたい場合は、ExploringES6をチェックしてください。この本はオンラインで無料で読むことができますが、著者のアクセル・ラウシュマイヤー博士を支援したい場合は、約30ドルで本を購入できます。

セットとES6を使用する場合は、Babel、ES6からES5へのトランスパイラー、およびそのポリフィルを使用できます。

編集:2017年6月6日の時点で、ほとんどの主要なブラウザーは最新バージョンで完全なセットサポートを備えています(IE 11を除く)。これは、古いブラウザをサポートする必要がない場合は、babelが必要ない可能性があることを意味します。現在のブラウザを含むさまざまなブラウザでの互換性を確認したい場合は、KangaxのES6互換性テーブルを確認してください。

編集:

初期化についての説明だけです。セットは、コンストラクターで任意の同期反復可能オブジェクトを取ることができます。つまり、配列だけでなく、文字列やイテレータも使用できます。たとえば、次の配列と文字列のセットの初期化を考えてみましょう。

const set1 = new Set(['a','a','b','b','c','c']);
console.log(...set1);
console.log(set1.size);
const set2 = new Set("aabbcc");
console.log(...set2);
console.log(set2.size);

配列と文字列の両方の出力は同じです。これ...set1スプレッド構文であることに注意してください。iterableの各要素が1つずつセットに追加されているように見えます。したがって、配列と文字列の両方が同じ要素を持ち、要素が同じ順序であるため、セットは同じように作成されます。セットについて注意すべきもう1つの点は、セットを反復する場合、反復順序は要素がセットに挿入された順序に従うことです。セットを反復処理する例を次に示します。

const set1 = new Set(['a','a','b','b','c','c']);
for(const element of set1) {
  console.log(element);
}

セットを初期化するために任意のイテレータを使用できるため、ジェネレータ関数からイテレータを使用することもできます。同じ出力を生成するイテレータ初期化の2つのそのような例を次に示します。

// a simple generator example
function* getLetters1 () {
  yield 'a';
  yield 'a';
  yield 'b';
  yield 'b';
  yield 'c';
  yield 'c';
}

// a somewhat more commonplace generator example
// with the same output as getLetters1.
function* getLetters2 (letters, repeatTimes) {
  for(const letter of letters) {
    for(let i = 0; i < repeatTimes; ++i) { 
      yield letter;
    }
  }
}

console.log("------ getLetters1 ------");
console.log(...getLetters1());
const set3 = new Set(getLetters1());
console.log(...set3);
console.log(set3.size);

console.log("------ getLetters2 ------");
console.log(...getLetters2('abc', 2));
const set4 = new Set(getLetters2('abc', 2));
console.log(...set4);
console.log(set4.size);

これらの例のジェネレーター関数は、繰り返さないように記述できますが、ジェネレーター関数がより複雑で、以下がパフォーマンスに悪影響を与えない限り、Setメソッドを使用して、ジェネレーターから値を取得しないようにすることができます。繰り返さないでください。

Rauschmayer博士の本の章を読まずにセットについて詳しく知りたい場合は、SetのMDNドキュメントを確認してください。MDNはまた、複数のそのような使用のようなセットを反復処理の例有しforEach及び使用.keys.values及び.entries方法を。MDNには、集合和集合、集合交差、集合差、対称集合差、集合スーパーセットチェックなどの例もあります。うまくいけば、それらの操作のほとんどは、それらをサポートする独自の関数を構築する必要なしに、JavaScriptで利用できるようになります。実際、新しいSetメソッドに関するこのTC39提案があり、提案がステージ4に達した場合、将来のある時点で次のメソッドをJavaScriptのSetに追加する必要があります。

  • Set.prototype.intersection(iterable)-メソッドは、setintersection操作によって新しいSetインスタンスを作成します。
  • Set.prototype.union(iterable)-メソッドは、setunion操作によって新しいSetインスタンスを作成します。
  • Set.prototype.difference(iterable)-メソッドは、iterableに要素が存在しない新しいSetを作成します。
  • Set.prototype.symmetricDifference(iterable)-thisまたはiterableのいずれかでのみ見つかった要素のセットを返します。
  • Set.prototype.isSubsetOf(iterable)
  • Set.prototype.isDisjointFrom(iterable)
  • Set.prototype.isSupersetOf(iterable)

また、セット自体は反復可能であるため、他のセットでセットを初期化してコピーを作成したり、和集合操作のためにnew Set([... setA、... setB])のようなことを実行したりできます。
ジョン

1
@LanceKind配列だけでなく、反復可能な任意のセットを初期化できることを示すなど、いくつかの追加情報を追加しました。
ジョン

32

私はdictオブジェクトをセットとして使用します。これは文字列と数値で機能しますが、カスタムの等価演算子と比較演算子を使用してオブジェクトのセットが必要な場合は、問題が発生すると思います。

セットの作成:

var example_set = 
{
    'a':true,
    'b':true,
    'c':true
}

セットに含めるためのテスト

if( example_set['a'] ){
    alert('"a" is in set');
}

セットへの要素の追加

example_set['d'] = true;

セットから要素を削除する

delete example_set['a'];


1
私が取り組んでいたコードは、をサポートしていない古いバージョンのエンジンを使用していましたSet。これは役に立ちました。
Abhijith Madhav 2016

16

セットは重複エントリを許可せず、通常、事前定義された順序を保証しません。配列はこれらの両方を実行するため、セットであるという意味に違反します(追加のチェックを行わない限り)。


2
配列は重複するエントリをフィルタリングしません...たとえば、Objective-CのNSSetのようにarr.push({id:1、name: "Jake"}):)
iTux 2015

あなたがそれをmot-a-motとすると、いいえ。ただし、IDを配列(マップ)キーとして使用できます。 arr[id] = {"name": "Jake"};
バッファロー

11

最初の方法は慣用的なJavaScriptです。

キーと値のペアを保存するときはいつでも、JavaScriptオブジェクトを使用する必要があります。配列に関しては、いくつかの問題があります。

  1. インデックスは数値です。

  2. ループせずに値が配列内にあるかどうかを確認する簡単な方法はありません。

  3. セットは重複を許可しません。配列はそうします。


プロパティ値に割り当てるのに最適なものは何ですか?
helpermethod 2011

1
JavaScript配列から重複する要素を削除することが可能です。stackoverflow.com/a/12166248/975097
アンダーソングリーン

9

配列からセットを作成する場合は、次のようにします。

let arr = [1, 1, 2, 1, 3];
let mySet = new Set(arr); // Set { 1, 2, 3 }

これは、Pythonでプログラミングするときに私が非常に夢中になった砂糖の構文であり、ES6がついに同じことを可能にしたことをうれしく思います。

注:それから私が言ったことはあなたの質問に直接答えなかったことに気づきます。ES5でこの「ハック」が発生する理由は、キーによるオブジェクトのルックアップ時間が配列(O(n))よりも大幅に高速(O(1))であるためです。パフォーマンスが重要なアプリケーションでは、このビットの読みやすさや直感を犠牲にして、パフォーマンスを向上させることができます。

しかし、2017年へようこそ。ここでは、すべての主要な最新ブラウザーで適切なセットを使用できます。


6

ES6/に設定ES2015

ES6/ES2015セットが組み込まれました。セットは、プリミティブ値であろうとオブジェクト参照であろうと、任意のタイプの一意の値の格納を可能にするデータ構造です。セットは、ES6組み込みのセットコンストラクターを使用して次の方法で宣言できます。

const set = new Set([1, 2, 3, 4, 5]);

Setコンストラクターを使用してセットを作成する場合、新しく作成されたセットオブジェクトは Set.prototype。これには、あらゆる種類の補助メソッドとプロパティがあります。これにより、次のことを簡単に行うことができます。

例:

const set = new Set([1, 2, 3, 4, 5]);

// checkout the size of the set
console.log('size is: ' + set.size);

// has method returns a boolean, true if the item is in the set
console.log(set.has(1));

// add a number
set.add(6);

// delete a number
set.delete(1);

// iterate over each element using a callback
set.forEach((el) => {
  console.log(el);
});

// remove all the entries from the set
set.clear();

ブラウザの互換性:

一部の機能が欠落しているIEを除き、すべての主要なブラウザがセットを完全にサポートするようになりました。正確なリファレンスについては、mdndocsを参照してください。


@Velojet:わかりました、十分に公平です。
kjhughes

3

裸のJavaScriptオブジェクトを使用してセットをエミュレートすることには2つの問題があります。1つは、オブジェクトが「in」演算子をねじ込む継承プロパティを持つことができること、もう1つは、この方法でのみスカラー値を格納できることです。オブジェクトのセットを作成することはできません。可能。したがって、Setsの現実的な実装では、プレーンおよびプロパティの割り当てではなく、メソッドaddを提供する必要があります。containsin


@kojiro:キーとして使用すると、オブジェクトは文字列に変換されます:set={};set[{x:1}]=123;alert(set[{z:99}])
georg

3

あなたが試すことができます Buckets。これはjavascriptデータ構造ライブラリであり、セットを操作するために必要なすべてが揃っています。


addAll(array)メソッドを提供しますか?
jorrebor 2013年

1

Setオブジェクトの基本的な作成と使用法🔷

let mySet = new Set()

mySet.add(2)         // Set {2}
mySet.add(7)         // Set {2, 7}
mySet.add(7)         // Set {2, 7}
mySet.add('my text') // Set {2, 7, 'my text'}
let myObj = { a: 1, b: 2 }
mySet.add(myObj)     // Set {2, 7, 'my text', {...}}
mySet.has(2)         // true
mySet.has(myObj)     // true
mySet.size           // 4

反復

for (let item of mySet) console.log(item)  // 2, 7, 'my text', {a:1, b:2}
mySet.forEach(value => console.log(value)) // 2, 7, 'my text', {a:1, b:2}

配列に変換

var myArr = Array.from(mySet)             // [2, 7, 'my text', {a:1, b:2}]

❕セットが提供する最も明確な機能は、セットオブジェクトのすべての値が一意である必要があることです。したがって、重複する値を追加することはできません。

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