Wie finde ich die Indizes aller Vorkommen eines Elements im Array?
Lesezeit: 6 Minuten
norddum
Ich versuche, die Indizes aller Instanzen eines Elements, sagen wir “Nano”, in einem JavaScript-Array zu finden.
var Cars = ["Nano", "Volvo", "BMW", "Nano", "VW", "Nano"];
Ich habe es versucht jQuery.inArrayoder ähnlich, .Index von()aber es gab nur den Index der letzten Instanz des Elements, dh in diesem Fall 5.
Wie bekomme ich es für alle Instanzen?
nnnnn
Die .indexOf() Methode hat einen optionalen zweiten Parameter, der den Index angibt, ab dem die Suche beginnen soll, sodass Sie ihn in einer Schleife aufrufen können, um alle Instanzen eines bestimmten Werts zu finden:
function getAllIndexes(arr, val) {
var indexes = [], i = -1;
while ((i = arr.indexOf(val, i+1)) != -1){
indexes.push(i);
}
return indexes;
}
var indexes = getAllIndexes(Cars, "Nano");
Sie machen nicht wirklich klar, wie Sie die Indizes verwenden möchten, also gibt meine Funktion sie als Array zurück (oder gibt ein leeres Array zurück, wenn der Wert nicht gefunden wird), aber Sie könnten etwas anderes mit den einzelnen Indexwerten machen innerhalb der Schleife.
UPDATE: Laut dem Kommentar von VisioN würde eine einfache for-Schleife die gleiche Aufgabe effizienter erledigen, und sie ist einfacher zu verstehen und daher einfacher zu warten:
function getAllIndexes(arr, val) {
var indexes = [], i;
for(i = 0; i < arr.length; i++)
if (arr[i] === val)
indexes.push(i);
return indexes;
}
Es scheint nicht die schnellere Alternative zu einer Single zu sein for Schleife mit Füllen des Index-Arrays.
– Vision
27. Dezember 2013 um 10:04 Uhr
@VisioN – Ja, eine einfache for-Schleife, die über das Array iteriert, wäre auch einfacher, aber da das OP erwähnt hat, versucht es zu verwenden .indexOf() Ich wollte zeigen, dass es funktionieren kann. (Ich denke, ich dachte, das OP könnte herausfinden, wie es mit einer for-Schleife geht.) Natürlich gibt es andere Möglichkeiten, dies zu tun, z. Cars.reduce(function(a, v, i) { if (v==="Nano") a.push(i); return a; }, []);
– nnnnn
27. Dezember 2013 um 10:07 Uhr
Ich kann sagen, dass du aus Nordamerika kommst, weil du benutzt hast indexes anstatt indices 😛
– 4 Schloss
14. April 2016 um 21:22 Uhr
@4castle – Ha. Nein, bin ich nicht. “Indizes” und “Indizes” sind beide richtig, und ich neige dazu, zwischen den beiden zu wechseln. Ich hatte das nie als regionales Dialekt-Ding betrachtet. Interessant.
– nnnnn
14. April 2016 um 22:31 Uhr
@IgorFomenko – Danke für den Vorschlag. Es ist nicht wirklich eine “Berechnung”, es ist nur eine Eigenschaftssuche, aber tatsächlich mache ich oft Codeschleifen gemäß Ihrem Vorschlag, aber ich mache es normalerweise nicht in StackOverflow-Antworten, wenn es nicht direkt relevant für die Frage ist. Wie sicher sind Sie, dass der JS-Compiler diese Optimierung nicht automatisch hinter den Kulissen durchführt?
+1. Lustiger Zufall: Ich habe gerade meine Antwort auf Ihren Kommentar unter meiner Antwort bearbeitet, um genau diese Lösung vorzuschlagen, dann aktualisiere ich und sehe, dass Sie bereits dasselbe mit nur einem anderen Variablennamen codiert haben.
– nnnnn
27. Dezember 2013 um 10:15 Uhr
@nnnnn :) Ja, ich dachte vielleicht reduce könnte eine schöne Alternative sein.
– Vision
27. Dezember 2013 um 10:16 Uhr
array.reduce((a, e, i) => (e === value) ? a.concat(i) : a, [])
– yckart
21. Dezember 2016 um 20:46 Uhr
Ich habe gegoogelt contat ist langsamer als pushdeshalb bleibe ich bei der Antwort.
– André Elrico
19. September 2019 um 8:16 Uhr
Ja, bitte nicht verwenden concat hier – Sie weisen bei jedem Rückruf ein ganz neues Array-Objekt zu und werfen das vorherige Objekt in den Garbage Collector, ohne dass die Lesbarkeit entsprechend verbessert wird.
var indices = array.map((e, i) => e === value ? i : '').filter(String)
super, es funktioniert. Können Sie erklären, was die Rolle des Filters ist (String)
– Muthamischtschelwan. v
3. Januar 2018 um 19:40 Uhr
@Muthu map(…) prüft bei jeder Iteration auf die Gleichheit von e und value. Bei Übereinstimmung wird der Index zurückgegeben, ansonsten ein leerer String. Um diese falschen Werte loszuwerden, filter(String) stellt sicher, dass das Ergebnis nur Werte enthält, die vom Typ Zeichenfolge und NICHT leer sind. filter(String) könnte auch geschrieben werden als: filter(e => e !== '')
– yckart
6. Januar 2018 um 19:13 Uhr
…oder: String(thing) zwingt irgendetwas zu einer Zeichenfolge. Array#filter gibt ein Array aller Werte zurück, für die die Bedingung gilt Wahrheit. Weil leere Zeichenfolgen sind falschdiese sind NICHT im Array enthalten.
– yckart
6. Januar 2018 um 19:13 Uhr
Danke für deine Erklärung, das hilft mir wirklich weiter
– Muthamischtschelwan. v
7. Januar 2018 um 17:32 Uhr
Ich wäre verwirrt, wenn ich das in einem Projekt sehen würde. Es liest sich wie “In Strings filtern”, was bedeutet, nur behalten, wenn es sich um einen String handelt. Und dann wäre das resultierende Array Indizes als Strings, nicht als Zahlen.
Sie können eine einfach lesbare Lösung dafür schreiben, indem Sie beide verwenden map und filter:
const nanoIndexes = Cars
.map((car, i) => car === 'Nano' ? i : -1)
.filter(index => index !== -1);
BEARBEITEN: Wenn Sie IE/Edge nicht unterstützen müssen (oder Ihren Code transpilieren), hat uns ES2019 gegeben flachKartemit dem Sie dies in einem einfachen Einzeiler tun können:
const nanoIndexes = Cars.flatMap((car, i) => car === 'Nano' ? i : []);
Ich mochte diese Antwort. Aber wie wäre es mit: Ändern zu diesem: .map((car, i) => car === 'Nano' ? i : null).filter(i => i);
– Anton vBR
16. April 2022 um 19:09 Uhr
Beides funktioniert. Das Problem bei der Verwendung einer Nichtzahl wie null besteht darin, dass die Eingabe in TypeScript viel lästiger wird. Wenn Sie nur JavaScript verwenden, funktioniert null einwandfrei.
– Zac Delventhal
17. April 2022 um 1:31 Uhr
JKhan
Ich möchte nur mit einer anderen einfachen Methode aktualisieren.
Sie können auch die forEach-Methode verwenden.
var Cars = ["Nano", "Volvo", "BMW", "Nano", "VW", "Nano"];
var result = [];
Cars.forEach((car, index) => car === 'Nano' ? result.push(index) : null)
Ich mochte diese Antwort. Aber wie wäre es mit: Ändern zu diesem: .map((car, i) => car === 'Nano' ? i : null).filter(i => i);
– Anton vBR
16. April 2022 um 19:09 Uhr
Beides funktioniert. Das Problem bei der Verwendung einer Nichtzahl wie null besteht darin, dass die Eingabe in TypeScript viel lästiger wird. Wenn Sie nur JavaScript verwenden, funktioniert null einwandfrei.