Wie kann ich ein Set in JavaScript zuordnen/reduzieren/filtern?

Lesezeit: 6 Minuten

Benutzer-Avatar
Mulan

Gibt es eine Möglichkeit map/reduce/filter/etc a Set in JavaScript oder muss ich meine eigene schreiben?

Hier ist etwas Vernünftiges Set.prototype Erweiterungen

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

Nehmen wir ein kleines Set

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

Und einige dumme kleine Funktionen

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

Und sehen Sie, wie sie funktionieren

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

Ist das nicht schön? Ja, das denke ich auch. Vergleichen Sie das mit der hässlichen Verwendung des Iterators

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

Und

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

Gibt es einen besseren Weg, dies zu erreichen map und reduce Verwendung einer Set in Javascript?

  • Das Problem mit Map-Reduce-ing a Set ist, dass Sets keine Funktoren sind.

    – Bartek Banachewicz

    20. Oktober 2015 um 10:53 Uhr

  • Nun, bedenke var s = new Set([1,2,3,4]); s.map((a) => 42);. Es ändert die Anzahl der Elemente, die map sollte normalerweise nicht gehen. Noch schlimmer, wenn Sie nur Teile der aufbewahrten Objekte vergleichen, denn dann ist technisch nicht festgelegt, welches Sie erhalten.

    – Bartek Banachewicz

    20. Oktober 2015 um 10:55 Uhr


  • Ich hatte das in Betracht gezogen, aber ich bin mir nicht sicher, ob ich (persönlich) das für ungültig halten würde. Okay also zumindest forEach existiert für dieses Szenario, aber warum nein reduce dann ?

    – Mulan

    20. Oktober 2015 um 10:58 Uhr

  • Ich würde sagen, das ist ein Versehen. Es ist völlig in Ordnung, ein Set zu falten (reduzieren).

    – Bartek Banachewicz

    20. Oktober 2015 um 10:59 Uhr


  • Etwas verwandte Lektüre: esdiscuss.org/topic/set-some-every-reduce-filter-map-methods

    – CodingIntrige

    20. Oktober 2015 um 11:01 Uhr

Benutzer-Avatar
ZephDavies

Ein kurzer Weg, dies zu tun, besteht darin, es über den Spread-Operator ES6 in ein Array zu konvertieren.

Dann stehen Ihnen alle Array-Funktionen zur Verfügung.

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

  • Da die Funktionen für Set! Dies ist eine vollständige, geführte und verständliche Problemumgehung, die in diesem Thema noch nicht vorhanden ist. Die Tatsache, dass es länger dauert, ist ein trauriger Preis für eine Problemumgehung, bis Set diese Funktionen implementiert!

    – ZephDavies

    7. März 2017 um 15:37 Uhr


  • Was ist der Unterschied zwischen this und Array.from

    – Peter

    21. Juni 2017 um 4:24 Uhr

  • Zumindest für mich ist der Unterschied zwischen diesem und Array.from ist das Array.from funktioniert mit TypeScript. Verwenden [...mySet] gibt den Fehler: TS2461: Type 'Set<number>' is not an array type.

    – Michal Madsen

    14. Juli 2017 um 13:18 Uhr

  • Für Spread vs Array.from() siehe stackoverflow.com/a/40549565/5516454 Grundsätzlich sind beide hier verwendbar. Array.from() kann zusätzlich Array-ähnliche Objekte ausführen, die die nicht implementieren @@iterator Methode.

    – ZephDavies

    24. Januar 2018 um 11:23 Uhr


  • Zumindest bei V8 ist das ein weiterer Unterschied [...mySet] schlägt bei großen Sets mit Stapelüberlauf fehl. Array.from() verwendet keinen Stapelspeicher pro Element, daher ist es weniger riskant, wenn die Anzahl der Elemente groß sein kann.

    – Peterflynn

    25. Mai um 21:20 Uhr

Benutzer-Avatar
Bartek Banachewicz

Um die Diskussion aus Kommentaren zusammenzufassen: Es gibt zwar keine technischen Gründe für die Einstellung nicht haben reducees wird derzeit nicht bereitgestellt und wir können nur hoffen, dass es sich in ES7 ändert.

Wie für mapes allein zu nennen, könnte die verletzen Set Einschränkung, daher könnte seine Anwesenheit hier umstritten sein.

Betrachten Sie die Zuordnung mit einer Funktion (a) => 42 – Es wird die Größe des Satzes auf 1 ändern, und dies könnte oder vielleicht auch nicht sei, was du wolltest.

Wenn Sie damit einverstanden sind, dagegen zu verstoßen, weil Sie zB sowieso folden, können Sie das anwenden map Teil auf jedem Element, kurz bevor Sie sie weitergeben reducewodurch akzeptiert wird, dass die Zwischensammlung (was an dieser Stelle kein Set ist), die reduziert werden soll, kann doppelte Elemente enthalten. Dies entspricht im Wesentlichen der Konvertierung in Array, um die Verarbeitung durchzuführen.

  • Dies ist meistens gut, außer (unter Verwendung des obigen Codes), s.map(a => 42) wird darin enden, dass Set { 42 } Das zugeordnete Ergebnis hat also eine andere Länge, aber es gibt keine “duplizierten” Elemente. Vielleicht aktualisieren Sie den Wortlaut und ich werde diese Antwort akzeptieren.

    – Mulan

    20. Oktober 2015 um 11:19 Uhr


  • @naomik Oh derp, ich habe gerade meinen ersten Kaffee getrunken, als ich das geschrieben habe. Auf den zweiten Blick reicht die Zwischensammlung zum Reduzieren könnte haben unmittelbare Elemente, wenn Sie akzeptieren, dass es sich nicht um eine Menge handelt – das meinte ich.

    – Bartek Banachewicz

    20. Oktober 2015 um 11:27 Uhr


  • Oh, ich verstehe – die Karte muss demselben Typ zugeordnet werden, daher mögliche Kollisionen im Zielsatz. Als ich diese Frage fand, dachte ich, map würde einem Array aus einem Satz zuordnen. (als ob Sie set.toArray().map()` getan hätten

    – Simon_Weaver

    4. Januar 2019 um 5:24 Uhr

  • In Scala und Haskell unterstützen Mengen eine Zuordnungsoperation – sie kann die Anzahl der Elemente in der Menge reduzieren.

    – Welizar Hristov

    21. Januar 2019 um 17:08 Uhr

Die Ursache für das Fehlen von map/reduce/filter an Map/Set Sammlungen scheinen hauptsächlich konzeptionelle Anliegen zu sein. Sollte jeder Sammlungstyp in Javascript tatsächlich seine eigenen iterativen Methoden angeben, nur um dies zu ermöglichen

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

Anstatt von

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

Eine Alternative wäre, map/reduce/filter als Teil des Iterable/Iterator-Protokolls anzugeben, da entries/values/keys Rückkehr Iterators. Denkbar ist aber, dass nicht jedes Iterable auch „mappable“ ist. Eine andere Alternative wäre, genau zu diesem Zweck ein separates „Sammelprotokoll“ vorzugeben.

Allerdings kenne ich die aktuelle Diskussion zu diesem Thema bei ES nicht.

  • Sollte jeder Sammlungstyp in Javascript tatsächlich seine eigenen iterativen Methoden angeben, nur um dies zu ermöglichen? Ja. Das alles Array.from mit new Set ist eine Problemumgehung und ist viel weniger lesbar als myArray.filter(isBiggerThan6Predicate); Jetzt muss ich selber schreiben filterSet Funktion, damit ich sauberen Code schreiben kann: filterSet(setWithNumbers, biggerThan6Predicate);

    – KulaGGin

    7. April um 12:18 Uhr


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

function filterSet(index) {
    set.delete([...set][index]);
}

filterSet(3); // Set { 1, 2, 3, 5, [size]: 4 }

dachte, dies sei eine ziemlich anständige Lösung zum “Filtern” des Sets.

1300330cookie-checkWie kann ich ein Set in JavaScript zuordnen/reduzieren/filtern?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy