Angenommen, ich habe Folgendes:
var array =
[
{"name":"Joe", "age":17},
{"name":"Bob", "age":17},
{"name":"Carl", "age": 35}
]
Was ist der beste Weg, um ein Array aller unterschiedlichen Altersstufen zu erhalten, sodass ich ein Ergebnis-Array von:
[17, 35]
Gibt es eine Möglichkeit, die Daten oder eine bessere Methode alternativ so zu strukturieren, dass ich nicht jedes Array durchlaufen muss, um den Wert von "age" zu überprüfen und anhand eines anderen Arrays auf seine Existenz zu prüfen und es hinzuzufügen, wenn nicht?
Wenn es eine Möglichkeit gäbe, könnte ich einfach die verschiedenen Zeitalter herausziehen, ohne zu iterieren ...
Derzeit ineffiziente Art und Weise möchte ich verbessern ... Wenn es bedeutet, dass anstelle von "Array" ein Array von Objekten, sondern eine "Karte" von Objekten mit einem eindeutigen Schlüssel (dh "1,2,3") wäre okay auch. Ich bin nur auf der Suche nach dem leistungsstärksten Weg.
Das Folgende ist, wie ich es derzeit mache, aber für mich scheint die Iteration aus Effizienzgründen nur mies zu sein, obwohl sie funktioniert ...
var distinct = []
for (var i = 0; i < array.length; i++)
if (array[i].age not in distinct)
distinct.push(array[i].age)
quelle
Set
Objekt undmap
s sind verschwenderisch. Dieser Job dauert nur eine einfache.reduce()
Phase.Antworten:
Wenn dies PHP wäre, würde ich ein Array mit den Schlüsseln erstellen und
array_keys
am Ende nehmen, aber JS hat keinen solchen Luxus. Versuchen Sie stattdessen Folgendes:quelle
array_unique
würde den gesamten Artikel vergleichen, nicht nur das Alter, wie hier gefragt wird.flags = {}
ist besser alsflags = []
age
eine relativ kleine ganze Zahl ist (<120 sicher)Wenn Sie ES6 / ES2015 oder höher verwenden, können Sie dies folgendermaßen tun:
Hier ist ein Beispiel dafür.
quelle
TypeError: (intermediate value).slice is not a function
mit ES6
quelle
array.filter((value, index, self) => self.map(x => x.age).indexOf(value.age) == index)
Sie könnten einen Wörterbuchansatz wie diesen verwenden. Grundsätzlich weisen Sie den Wert, den Sie als Schlüssel unterscheiden möchten, als "Wörterbuch" zu (hier verwenden wir ein Array als Objekt, um den Wörterbuchmodus zu vermeiden). Wenn der Schlüssel nicht vorhanden war, fügen Sie diesen Wert als eindeutig hinzu.
Hier ist eine funktionierende Demo:
Dies ist O (n), wobei n die Anzahl der Objekte im Array und m die Anzahl der eindeutigen Werte ist. Es gibt keinen schnelleren Weg als O (n), da Sie jeden Wert mindestens einmal überprüfen müssen.
In der vorherigen Version wurde ein Objekt und für in verwendet. Diese waren geringfügiger Natur und wurden seitdem oben geringfügig aktualisiert. Der Grund für einen scheinbaren Leistungszuwachs zwischen den beiden Versionen im ursprünglichen jsperf war jedoch, dass die Datenstichprobengröße so klein war. Der Hauptvergleich in der vorherigen Version befasste sich daher mit dem Unterschied zwischen der Verwendung der internen Karte und des Filters im Vergleich zu den Suchvorgängen im Wörterbuchmodus.
Ich habe den obigen Code aktualisiert, wie bereits erwähnt. Ich habe jedoch auch den jsperf aktualisiert, um 1000 statt 3 Objekte zu durchsuchen. 3 hat viele der damit verbundenen Leistungsprobleme übersehen ( veralteter jsperf ).
Performance
https://jsperf.com/filter-vs-dictionary-more-data Als ich dieses Wörterbuch ausführte, war es 96% schneller.
quelle
if( typeof(unique[array[i].age]) == "undefined"){ distinct.push(array[i].age); unique[array[i].age] = 0; }
So würden Sie dies mit dem neuen Set über ES6 für Typescript ab dem 25. August 2017 lösen
quelle
Mit den ES6-Funktionen können Sie Folgendes tun:
quelle
const uniqueObjects = [ ...new Set( array.map( obj => obj.age) ) ].map( age=> { return array.find(obj => obj.age === age) } )
Ich würde nur Dups zuordnen und entfernen:
Edit: Aight! Nicht der effizienteste Weg in Bezug auf die Leistung, aber der einfachste und am besten lesbare IMO. Wenn Sie sich wirklich für die Mikrooptimierung interessieren oder große Datenmengen haben, ist eine reguläre
for
Schleife "effizienter".quelle
if
s zu verwenden. Mit drei Millionen erhalten Sie sehr unterschiedliche Ergebnisse.ES6 Beispiel
quelle
Für diejenigen, die ein Objekt mit allen Eigenschaften zurückgeben möchten, die nach Schlüssel eindeutig sind
quelle
Es gibt bereits viele gültige Antworten, aber ich wollte eine hinzufügen, die nur die
reduce()
Methode verwendet, da sie sauber und einfach ist.Verwenden Sie es so:
quelle
Die
forEach
Version der Antwort von @ travis-j (hilfreich für moderne Browser und die Node JS-Welt):34% schneller in Chrome v29.0.1547: http://jsperf.com/filter-versus-dictionary/3
Und eine generische Lösung, die eine Mapper-Funktion übernimmt (etwas langsamer als die direkte Karte, aber das wird erwartet):
quelle
Ich habe standardmäßig damit begonnen, Underscore in alle neuen Projekte einzufügen, damit ich nie über diese kleinen Probleme beim Datenmunging nachdenken muss.
Produziert
[17, 35]
.quelle
Hier ist ein anderer Weg, um dies zu lösen:
Ich habe keine Ahnung, wie schnell diese Lösung im Vergleich zu den anderen ist, aber ich mag das sauberere Aussehen. ;-);
EDIT: Okay, das oben genannte scheint die langsamste Lösung von allen hier zu sein.
Ich habe hier einen Leistungstestfall erstellt: http://jsperf.com/distinct-values-from-array
Anstatt nach dem Alter (Integer) zu testen, habe ich die Namen (Strings) verglichen.
Methode 1 (TS-Lösung) ist sehr schnell. Interessanterweise übertrifft Methode 7 alle anderen Lösungen. Hier habe ich gerade .indexOf () entfernt und eine "manuelle" Implementierung verwendet, um das Aufrufen von Schleifenfunktionen zu vermeiden:
Der Leistungsunterschied bei Safari & Firefox ist erstaunlich und Chrome scheint bei der Optimierung die beste Arbeit zu leisten.
Ich bin mir nicht ganz sicher, warum die obigen Schnipsel im Vergleich zu den anderen so schnell sind. Vielleicht hat jemand, der klüger als ich ist, eine Antwort. ;-);
quelle
mit lodash
quelle
Verwenden von Lodash
Rückgabe [17,35]
quelle
quelle
underscore.js
_.uniq(_.pluck(array,"age"))
quelle
Hier ist eine vielseitige Lösung, die Reduzieren verwendet, Mapping ermöglicht und die Einfügereihenfolge beibehält.
Artikel : Ein Array
Mapper : Eine unäre Funktion, die das Element den Kriterien zuordnet oder leer ist, um das Element selbst zuzuordnen.
Verwendungszweck
Sie können dies Ihrem Array-Prototyp hinzufügen und den Parameter items weglassen, wenn dies Ihr Stil ist ...
Sie können auch ein Set anstelle eines Arrays verwenden, um den Abgleich zu beschleunigen.
quelle
quelle
Ich habe das gerade gefunden und fand es nützlich
Verwenden Sie wieder den Unterstrich . Wenn Sie also ein solches Objekt haben
Sie erhalten nur die eindeutigen Objekte.
Was hier passiert, ist, dass
indexBy
eine Karte wie diese zurückgegeben wirdund nur weil es eine Karte ist, sind alle Schlüssel eindeutig.
Dann ordne ich diese Liste einfach wieder dem Array zu.
Falls Sie nur die unterschiedlichen Werte benötigen
Denken Sie daran, dass das
key
als Zeichenfolge zurückgegeben wird. Wenn Sie stattdessen Ganzzahlen benötigen, sollten Sie dies tunquelle
Ich denke, Sie suchen nach GroupBy-Funktion (mit Lodash)
erzeugt Ergebnis:
jsFiddle-Demo: http://jsfiddle.net/4J2SX/201/
quelle
Wenn Sie wie ich eine "funktionalere" Version bevorzugen, ohne die Geschwindigkeit zu beeinträchtigen, wird in diesem Beispiel eine schnelle Wörterbuchsuche verwendet, die in den Verschluss reduziert ist.
Nach diesem Test ist meine Lösung doppelt so schnell wie die vorgeschlagene Antwort
quelle
quelle
Ich weiß, dass mein Code wenig lang und wenig zeitlich komplex ist, aber es ist verständlich, also habe ich es auf diese Weise versucht.
Ich versuche hier eine prototypbasierte Funktion zu entwickeln und auch den Code zu ändern.
Hier ist Distinct meine eigene Prototypfunktion.
quelle
Wenn Sie Array.prototype.includes haben oder bereit sind, es zu füllen , funktioniert dies:
quelle
Mein unten stehender Code zeigt das eindeutige Altersarray sowie das neue Array ohne doppeltes Alter
quelle
Ich habe mein eigenes in TypeScript geschrieben, für einen generischen Fall, wie den in Kotlins
Array.distinctBy {}
...Wo
U
ist Hashhable natürlich. Für Objekte benötigen Sie möglicherweise https://www.npmjs.com/package/es6-json-stable-stringifyquelle
Für den Fall, dass Sie ein Unikat des gesamten Objekts benötigen
[Objekt {x: 1, y: 2}, Objekt {x: 2, y: 1}]
quelle
Die Beantwortung dieser alten Frage ist ziemlich sinnlos, aber es gibt eine einfache Antwort, die auf die Natur von Javascript hinweist. Objekte in Javascript sind von Natur aus Hash-Tabellen. Wir können dies verwenden, um einen Hash eindeutiger Schlüssel zu erhalten:
Dann können wir den Hash auf ein Array eindeutiger Werte reduzieren:
Das ist alles was du brauchst. Das Array a2 enthält nur das eindeutige Alter.
quelle
Einfacher Einzeiler mit großartiger Leistung. 6% schneller als die ES6-Lösungen in meinen Tests .
quelle
array.map( o => o.age).filter( (v,i,a) => a.indexOf(v)===i)
. Ich benutze das Funktionsschlüsselwort jetzt so selten, dass ich Dinge zweimal lesen muss, wenn ich es sehe 😊