Möglichkeiten, ein Set in JavaScript zu erstellen?


82

In Eloquent JavaScript, Kapitel 4, wird eine Reihe von Werten erstellt, indem ein Objekt erstellt und die Werte als Eigenschaftsnamen gespeichert werden. Dabei werden beliebige Werte (z. B. true) als Eigenschaftswerte zugewiesen. Um zu überprüfen, ob der Wert bereits im Set enthalten ist, wird der inOperator verwendet:

var set = {};

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

Ist das idiomatisches JavaScript? Wäre es nicht noch besser, ein Array zu verwenden?

var set = [];

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

1
Wie würden Sie ein Array erwarten, für das 'Tom' in setes wahr aussieht? Es sieht sehr danach aus, als hätten Sie falsche Annahmen über etwas , und ich versuche herauszufinden, worüber .

10
Zu Ihrer Information, Sie brauchen Eltern : if(!('Tom' in set)). Derzeit bedeutet es false in setseit !'Tom' === false.
Pimvdb

ES6 hat Sätze, siehe Johns Antwort unten
Ben Taliadoros

Antworten:


101

Sets sind jetzt in ES2015 verfügbar (auch bekannt als ES6, dh ECMAScript 6). ES6 ist seit Juni 2015 der aktuelle Standard für JavaScript.

ECMAScript 6 hat die Datenstruktur Set, die für beliebige Werte funktioniert, schnell ist und NaN korrekt behandelt. - Axel Rauschmayer , Exploring ES6

Die ersten beiden Beispiele aus Axel Rauschmayers Buch Exploring ES6 :

Einzelne Elemente verwalten:

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

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

Bestimmen der Größe eines Sets und Löschen:

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

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

Ich würde Exploring ES6 ausprobieren, wenn Sie mehr über Sets in JavaScript erfahren möchten. Das Buch kann kostenlos online gelesen werden. Wenn Sie jedoch den Autor Dr. Axel Rauschmayer unterstützen möchten, können Sie das Buch für etwa 30 US-Dollar erwerben.

Wenn Sie jetzt Sets und ES6 verwenden möchten, können Sie Babel , den Transpiler ES6 zu ES5 und seine Polyfills verwenden.

Bearbeiten: Ab dem 6. Juni 2017 bieten die meisten gängigen Browser in ihren neuesten Versionen (außer IE 11) vollständige Set-Unterstützung. Dies bedeutet, dass Sie möglicherweise kein Babel benötigen, wenn Sie ältere Browser nicht unterstützen möchten. Wenn Sie die Kompatibilität in verschiedenen Browsern einschließlich Ihres aktuellen Browsers anzeigen möchten, überprüfen Sie die ES6-Kompatibilitätstabelle von Kangax .

BEARBEITEN:

Nur Klarstellung zur Initialisierung. Sets können jede synchrone Iteration in ihrem Konstruktor annehmen. Dies bedeutet, dass sie nicht nur Arrays, sondern auch Strings und Iteratoren verwenden können. Nehmen Sie zum Beispiel die folgende Array- und String-Initialisierung einer Menge:

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);

Beide Ausgänge des Arrays und des Strings sind gleich. Beachten Sie, dass dies ...set1die Spread-Syntax ist . Es scheint, dass jedes Element der Iterable einzeln zur Menge hinzugefügt wird. Da also sowohl das Array als auch die Zeichenfolge dieselben Elemente haben und die Elemente in derselben Reihenfolge sind, wird die Menge gleich erstellt. Eine andere Sache, die Sie bei Mengen beachten sollten, ist, dass beim Iterieren über sie die Iterationsreihenfolge der Reihenfolge folgt, in der die Elemente in die Menge eingefügt wurden. Hier ist ein Beispiel für das Durchlaufen einer Menge:

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

Da Sie zum Initialisieren eines Satzes jedes Iterable verwenden können, können Sie sogar einen Iterator aus einer Generatorfunktion verwenden . Hier sind zwei Beispiele für Iteratorinitialisierungen, die dieselbe Ausgabe erzeugen:

// 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);

Die Generatorfunktionen dieser Beispiele könnten nur so geschrieben werden, dass sie sich nicht wiederholen. Wenn die Generatorfunktion jedoch komplizierter ist und sich die Leistung nicht zu negativ auf das Folgende auswirkt, können Sie die Set-Methode verwenden, um nur Werte von einem Generator abzurufen, der dies nicht tut nicht wiederholen.

Wenn Sie mehr über Sets erfahren möchten, ohne das Kapitel von Dr. Rauschmayer in seinem Buch zu lesen, können Sie die MDN-Dokumente zu Set lesen . MDN hat auch weitere Beispiele für das Iterieren über einen Satz wie die Verwendung forEachund die Verwendung der .keys, .valuesund .entriesMethoden. MDN enthält auch Beispiele wie Mengenvereinigung, Mengenschnitt, Mengenunterschied, symmetrische Mengenunterschiede und Mengenüberprüfungsprüfung. Hoffentlich werden die meisten dieser Vorgänge in JavaScript verfügbar sein, ohne dass Sie eigene Funktionen erstellen müssen, die sie unterstützen. Tatsächlich gibt es diesen TC39-Vorschlag für neue Set-Methoden, die hoffentlich zu einem späteren Zeitpunkt die folgenden Methoden zu Set in JavaScript hinzufügen sollten, wenn der Vorschlag Stufe 4 erreicht:

  • Set.prototype.intersection (iterable) - Methode erstellt eine neue Set-Instanz durch Set-Schnittpunktoperation.
  • Set.prototype.union (iterable) - Methode erstellt eine neue Set-Instanz durch Set Union-Operation.
  • Set.prototype.difference (iterable) - Methode erstellt ein neues Set ohne Elemente, die in iterable vorhanden sind.
  • Set.prototype.symmetricDifference (iterable) - gibt eine Reihe von Elementen zurück, die nur in diesem oder in iterable gefunden wurden.
  • Set.prototype.isSubsetOf (iterierbar)
  • Set.prototype.isDisjointFrom (iterierbar)
  • Set.prototype.isSupersetOf (iterierbar)

Auch Sets selbst sind iterierbar, sodass Sie Sets mit anderen Sets initialisieren können, um eine Kopie zu erstellen, oder etwas wie ein neues Set ([... setA, ... setB]) für eine Vereinigungsoperation ausführen können.
John

1
@LanceKind Ich habe einige zusätzliche Informationen hinzugefügt, darunter das Zeigen, dass Sie Sets mit jedem iterierbaren Element initialisieren können, nicht nur mit Arrays.
John

32

Ich benutze Diktierobjekte als Mengen. Dies funktioniert mit Zeichenfolgen und Zahlen, aber ich nehme an, dies würde Probleme verursachen, wenn Sie eine Reihe von Objekten mit benutzerdefinierten Gleichheits- und Vergleichsoperatoren haben möchten:

Erstellen eines Sets:

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

Testen auf Aufnahme in einen Satz

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

Hinzufügen eines Elements zu einer Menge

example_set['d'] = true;

Entfernen eines Elements aus einer Menge

delete example_set['a'];;


1
Der Code, an dem ich arbeitete, verwendete eine ältere Version der Engine, die keine Unterstützung hatte Set. Das hat geholfen.
Abhijith Madhav

16

Sets erlauben keine doppelten Einträge und garantieren normalerweise keine vordefinierte Reihenfolge. Arrays machen beides und verletzen damit, was es bedeutet, ein Set zu sein (es sei denn, Sie führen zusätzliche Überprüfungen durch).


2
Array filtert keine doppelten Einträge ... zum Beispiel arr.push ({id: 1, name: "Jake"}) wie als NSSet in Objective-C :)
iTux

Wenn Sie es mot-a-mot nehmen, nein. Sie können jedoch einfach die ID als Array-Schlüssel (Map-Schlüssel) verwenden. arr[id] = {"name": "Jake"};
Buffalo

11

Der erste Weg ist idiomatisches JavaScript.

Jedes Mal, wenn Sie ein Schlüssel / Wert-Paar speichern möchten, müssen Sie ein JavaScript-Objekt verwenden. Bei Arrays gibt es mehrere Probleme:

  1. Der Index ist ein numerischer Wert.

  2. Keine einfache Möglichkeit, um zu überprüfen, ob sich ein Wert in einem Array befindet, ohne eine Schleife durchzuführen.

  3. Ein Set erlaubt keine Duplikate. Ein Array tut es.


Was ist am besten dem Eigenschaftswert zuzuordnen?
Hilfsmethode

1
Es ist möglich, doppelte Elemente aus JavaScript-Arrays zu entfernen. stackoverflow.com/a/12166248/975097
Anderson Green

9

Wenn Sie einen Satz aus einem Array erstellen möchten, gehen Sie einfach wie folgt vor:

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

Dies ist eine Zuckersyntax, die ich mir beim Programmieren in Python sehr vorgestellt habe. Ich bin so froh, dass ES6 es endlich möglich gemacht hat, dasselbe zu tun.

HINWEIS: Dann wird mir klar, dass das, was ich gesagt habe, Ihre Frage nicht direkt beantwortet hat. Der Grund, warum Sie diesen "Hack" in ES5 haben, ist, dass die Suchzeit in einem Objekt nach Schlüsseln erheblich schneller ist (O (1)) als in einem Array (O (n)). In leistungskritischen Anwendungen können Sie diese Lesbarkeit oder Intuition für eine bessere Leistung opfern.

Aber hey, willkommen in 2017, wo Sie das richtige Set jetzt in allen gängigen modernen Browsern verwenden können!


6

Setzt in ES6/ ES2015:

ES6Ich habe ES2015jetzt Sets eingebaut. Ein Satz ist eine Datenstruktur, die die Speicherung eindeutiger Werte eines beliebigen Typs ermöglicht, unabhängig davon, ob es sich um primitive Werte oder Objektreferenzen handelt. Eine Menge kann mit dem ES6eingebauten Mengenkonstruktor folgendermaßen deklariert werden:

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

Beim Erstellen eines Sets mit dem Set-Konstruktor erbt unser neu erstelltes Set-Objekt von Set.prototype. Dies hat alle Arten von Hilfsmethoden und -eigenschaften. Auf diese Weise können Sie auf einfache Weise die folgenden Dinge tun:

Beispiel:

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();

Browser-Kompatibilität:

Alle gängigen Browser unterstützen jetzt Sets mit Ausnahme des IE, in dem einige Funktionen fehlen. Eine genaue Referenz finden Sie in den MDN-Dokumenten .


@ Velojet: Ok, fair genug.
kjhughes

3

Es gibt zwei Probleme bei der Verwendung von Bare-Javascript-Objekten zum Emulieren von Mengen: Erstens kann ein Objekt eine geerbte Eigenschaft haben, die den Operator "in" verschraubt, und zweitens können Sie nur skalare Werte auf diese Weise speichern, eine Menge von Objekten jedoch nicht möglich. Daher soll eine realistische Umsetzung von Sets Methoden bieten addund containsanstelle von einfachen inund Eigenschaftszuweisungen.


@kojiro: Objekte werden in Zeichenketten umgewandelt , wenn sie als Schlüssel verwendet:set={};set[{x:1}]=123;alert(set[{z:99}])
georg

3

Sie können Buckets ausprobieren , ist eine Javascript-Datenstrukturbibliothek und verfügt über alles, was Sie zum Bearbeiten von Sets benötigen.


Bietet es eine addAll (Array) -Methode?
Jorrebor

1

Grundlegende Erstellung und Verwendung des Set-Objekts 🔷

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

Wiederholung

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}

In Array konvertieren

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

❕ Das deutlichste Merkmal, das Set bietet, ist, dass jeder Wert im Set-Objekt eindeutig sein muss. Sie können also keine doppelten Werte hinzufügen.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.