In einem Array von Objekten der schnellste Weg, um den Index eines Objekts zu finden, dessen Attribute mit einer Suche übereinstimmen

135

Ich habe ein wenig herumgesurft, um einen effizienten Weg zu finden, bin aber nirgendwo hingekommen. Ich habe eine Reihe von Objekten, die so aussehen:

array[i].id = some number;
array[i].name = some name;

Was ich tun möchte, ist, die INDEXE der Objekte zu finden, bei denen id beispielsweise einem von 0,1,2,3 oder 4 entspricht. Ich nehme an, ich könnte einfach so etwas tun:

var indexes = [];
for(i=0; i<array.length; i++) {
  (array[i].id === 0) ? { indexes[0] = i }
  (array[i].id === 1) ? { indexes[1] = i }
  (array[i].id === 2) ? { indexes[2] = i }
  (array[i].id === 3) ? { indexes[3] = i }
  (array[i].id === 4) ? { indexes[4] = i }
}

Dies würde zwar funktionieren, scheint aber ziemlich teuer und langsam zu sein (ganz zu schweigen von hässlich), insbesondere wenn array.length groß sein könnte. Irgendwelche Ideen, wie man das ein bisschen aufpeppen kann? Ich dachte daran, array.indexOf irgendwie zu verwenden, aber ich sehe nicht, wie ich die Syntax erzwingen soll. Dies

array.indexOf(this.id === 0);

Gibt beispielsweise undefiniert zurück, wie es wahrscheinlich sollte. Danke im Voraus!

Petrov
quelle
1
Wenn Sie ein einfaches altes Array haben, können Sie nur iterieren. Das sind Arrays, eine Reihe von Objekten, die nach Array-Index geordnet sind.
Dave Newton
2
Kommen Sie heute auf diesen Beitrag, für alle Nachzügler gibt es eine neue Array-Methode Array.prototype.findIndex()in ECMAScript 2015. Die akzeptierte Antwort war großartig.
Conrad Lo
Ich bin ein Fan der ES6-Syntax (verwenden Sie Polyfills, wenn Unterstützung für ältere Browser benötigt wird). ES7 + ES8 werden Zukunft sein
Fr0zenFyr

Antworten:

391

Vielleicht möchten Sie Funktionen höherer Ordnung wie "Karte" verwenden. Angenommen, Sie möchten nach dem Attribut "Feld" suchen:

var elementPos = array.map(function(x) {return x.id; }).indexOf(idYourAreLookingFor);
var objectFound = array[elementPos];
Pablo Francisco Pérez Hidalgo
quelle
9
Diese Antwort ist groß , weil es tatsächlich die Frage beantwortet , indem der Index :) Bereitstellung
counterbeing
3
@ZeroAbsolute Ihre angewendete Funktion (an Map übergeben) kann eine Hash-Zeichenfolge zurückgeben, die für jede mögliche Kombination, die durch Ihre Kriterien angegeben wird, einen eindeutigen Schlüssel bereitstellen sollte. Zum Beispiel : function hashf(el) { return String(el.id) + "_" + String(el.name); }. Dies ist nur ein Hinweis: elementPos = array.map(hashf(x)).indexOf(hash({id:3, name:'Pablo'}));Natürlich ist die von mir bereitgestellte Hash-Funktion nicht für alle Fälle gültig, da '_'sie Teil Ihrer Werte sein könnte, aber es ist nur ein kurzes Beispiel, wie Sie verschiedene Hash-Methoden herausfinden können.
Pablo Francisco Pérez Hidalgo
1
Was gibt das zurück, wenn es nicht gefunden wird? Ich nehme -1 an, nur neugierig. Ich werde experimentieren.
Nathan C. Tresch
1
@ NathanC.Tresch Es wird -1 zurückgegeben, da dies ein indexOfRückgabewert ist, wenn ein bestimmter Wert nicht gefunden werden kann.
Pablo Francisco Pérez Hidalgo
2
Hallo allerseits, anstatt zwei Methoden zu verwenden map, indexOf, können Sie nur eine verwenden, die findIndex....... heißt. Beispiel :[{id:1},{id:2},{id:3},{id:4}].findIndex(function(obj){return obj.id == 3}) OR [{id:1},{id:2},{id:3},{id:4}].findIndex(obj => obj.id == 3)
Umair Ahmed
64

Der einfachste und einfachste Weg, um einen Elementindex im Array zu finden.

ES5-Syntax: [{id:1},{id:2},{id:3},{id:4}].findIndex(function(obj){return obj.id == 3})

ES6-Syntax: [{id:1},{id:2},{id:3},{id:4}].findIndex(obj => obj.id == 3)

Umair Ahmed
quelle
4
Ich glaube, das ist die eleganteste Lösung. Für diejenigen, die sich Sorgen um die Abwärtskompatibilität machen, finden Sie die Polyfill für findIndexunter developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
mrogers
2
In meinem ES6-Flusenwerkzeug wird eine Warnung angezeigt, dass der obj.id == 3hier verwendete Operator eine unerwartete Typkonvertierung verursachen kann. Verwenden Sie obj.id === 3stattdessen den Operator, der auf gleichen Wert und Typ prüft.
Thclark
1
Diese Antwort ist mindestens 3,5-mal schneller als die oben akzeptierte Antwort. Die Verwendung var elementPos = array.map(function(x) {return x.id; }).indexOf(idYourAreLookingFor);dauerte 0,03500000002532033 Millisekunden. Die Verwendung [{id:1},{id:2},{id:3},{id:4}].findIndex(obj => obj.id == 3)dauerte 0,00999999747378752 Millisekunden.
Ovidio Reyna
1
DIESE ANTWORT ist die EFFIZIENTSTE, da sie nicht das gesamte Array iteriert. Die ausgewählte Antwort ordnet das gesamte Array zu und findet dann den Index, der das gesamte Array einmal durchlaufen muss
Karun
26

Die neue Array-Methode .filter () würde dafür gut funktionieren:

var filteredArray = array.filter(function (element) { 
    return element.id === 0;
});

jQuery kann dies auch mit .grep () tun

Bearbeiten: Es ist erwähnenswert, dass diese beiden Funktionen nur unter der Haube durchlaufen werden. Es gibt keinen merklichen Leistungsunterschied zwischen ihnen und dem Rollen Ihrer eigenen Filterfunktion, aber warum sollten Sie das Rad neu erfinden?

jbabey
quelle
+1, ich vergesse immer solche eingebauten Funktionen für Objekte.
Tejs
59
Dies gibt keinen Index zurück.
Adam Grant
Dies beantwortet diese spezielle Frage nicht, hilft mir aber sehr! Vielen Dank!
Rochasdv
Dies gibt den Index nicht zurück.
Rich
10

Wenn Sie über die Leistung kümmern, tun sie nicht mit gehen finden oder Filter oder Karte oder einen der oben diskutierten Verfahren

Hier ist ein Beispiel, das die schnellste Methode demonstriert. HIER ist der Link zum eigentlichen Test

Setup-Block

var items = []

for(var i = 0; i < 1000; i++) {
    items.push({id: i + 1})
}

var find = 523

Schnellste Methode

var index = -1
for(var i = 0; i < items.length; i++) {
    if(items[i].id === find) {
        index = i;
        break;
    }
}

Langsamere Methoden

items.findIndex(item => item.id === find)

LANGSAMSTE Methode

items.map(item => item.id).indexOf(find);
PirateApp
quelle
2
Vielen Dank für diesen Vergleich! Sehr interessant ist, wie stark die Leistung variiert - einschließlich der Methode, die schneller ist, je nachdem, mit welcher Browser- / JavaScript-Engine sie ausgeführt wurden.
Iain Collins
1
Ich denke, dies sollte als Antwort markiert werden. Dies zeigt den schnellsten und langsameren Weg.
Schmerzmittel
In Ihrem Benchmark ist Block 2 (mit findIndex) für mich tatsächlich schneller (unter Microsoft Edge Chromium 83.0.474.0)
rezadru
Block 2 ist jetzt auch auf Chrom schneller
Cody Mikol
8
array.forEach(function (elem, i) {  // iterate over all elements of array
    indexes[elem.id] = i;           // take the found id as index for the
});                                 // indexes array and assign i

Das Ergebnis ist eine Nachschlageliste für die ID. Mit der angegebenen ID erhalten wir den Index des Datensatzes.

Nina Scholz
quelle
6
var indices = [];
var IDs = [0, 1, 2, 3, 4];

for(var i = 0, len = array.length; i < len; i++) {
    for(var j = 0; j < IDs.length; j++) {
        if(array[i].id == ID) indices.push(i);
    }
}
Elliot Bonneville
quelle
6

Da es keine Antwort mit normalem Array gibt find:

var one = {id: 1, name: 'one'};
var two = {id: 2, name:'two'}
var arr = [one, two] 

var found = arr.find((a) => a.id === 2)

found === two // true

arr.indexOf(found) // 1
enapupe
quelle
3

Ein neuer Weg mit ES6

let picked_element = array.filter(element => element.id === 0);
Silve2611
quelle
picked_elementist ein Array in diesem Fall ...
Heretic Monkey
3

const index = array.findIndex(item => item.id === 'your-id');

Dadurch sollten Sie den Index des Elements im Array mit der ID === your-id erhalten

array = [ {id:1}, {id:2} ];

const index = array.findIndex(item => item.id === 2);

console.log(index);

PulpDood
quelle
2

Klingt für mich so, als könnten Sie einen einfachen Iterator mit einem Rückruf zum Testen erstellen. Wie so:

function findElements(array, predicate)
{
    var matchingIndices = [];

    for(var j = 0; j < array.length; j++)
    {
        if(predicate(array[j]))
           matchingIndices.push(j);
    }

    return matchingIndices;
}

Dann könnten Sie so aufrufen:

var someArray = [
     { id: 1, text: "Hello" },
     { id: 2, text: "World" },
     { id: 3, text: "Sup" },
     { id: 4, text: "Dawg" }
  ];

var matchingIndices = findElements(someArray, function(item)
   {
        return item.id % 2 == 0;
   });

// Should have an array of [1, 3] as the indexes that matched
Tejs
quelle
2

Ich habe Tejs 'Antwort für mongoDB und Robomongo angepasst und mich geändert

matchingIndices.push(j);

zu

matchingIndices.push(NumberInt(j+1));
user2584621
quelle
2

Verwenden der ES6- mapFunktion:

let idToFind = 3;
let index = someArray.map(obj => obj.id).indexOf(idToFind);
JoeTidee
quelle
2

Um alle oben genannten großartigen Antworten und zusätzlich meine Antwort bezüglich der Suche nach allen Indizes zusammenzufassen, die aus einigen Kommentaren hervorgegangen sind.

  1. Rückgabe des Index des ersten Auftretens.

const array = [{ id: 1 }, { id: 2 }, { id: 3 }, { id: 4 }, { id: 2 }];
const idYourAreLookingFor = 2;

//ES5 
//Output: 1
array.map(function (x) { return x.id; }).indexOf(idYourAreLookingFor);

//ES6 
//Output: 1
array.findIndex(obj => obj.id === idYourAreLookingFor);

  1. Verwenden Sie reduzieren, um das Indexarray aller Vorkommen zurückzugeben.

const array = [{ id: 1 }, { id: 2 }, { id: 3 }, { id: 4 }, { id: 2 }]
const idYourAreLookingFor = 2;

//ES5
//Output: [1, 4]
array.reduce(function (acc, obj, i) {
  if (obj.id === idYourAreLookingFor)
    acc.push(i);
  return acc;
}, []);

//ES6
//Output: [1, 4]
array.reduce((acc, obj, i) => (obj.id === idYourAreLookingFor) ? acc.concat(i) : acc, [])

trungk18
quelle
0

Da ich noch keinen Kommentar abgeben kann, möchte ich die Lösung zeigen, die ich basierend auf der von Umair Ahmed veröffentlichten Methode verwendet habe. Wenn Sie jedoch nach einem Schlüssel anstelle eines Werts suchen möchten:

[{"a":true}, {"f":true}, {"g":false}]
.findIndex(function(element){return Object.keys(element)[0] == "g"});

Ich verstehe, dass es die erweiterte Frage nicht beantwortet, aber der Titel gibt nicht an, was von jedem Objekt gewünscht wurde. Deshalb möchte ich dies demütig teilen, um anderen in Zukunft Kopfschmerzen zu ersparen, während ich es nicht starten kann schnellste Lösung.

Xander N.
quelle
0

Ich habe ein kleines Dienstprogramm namens Super-Array erstellt, mit dem Sie über eine eindeutige Kennung mit O (1) -Komplexität auf Elemente in einem Array zugreifen können. Beispiel:

const SuperArray = require('super-array');

const myArray = new SuperArray([
  {id: 'ab1', name: 'John'},
  {id: 'ab2', name: 'Peter'},
]);

console.log(myArray.get('ab1')); // {id: 'ab1', name: 'John'}
console.log(myArray.get('ab2')); // {id: 'ab2', name: 'Peter'}
Patotom
quelle
Vielleicht möchten Sie lesen, wie man persönliche Open-Source-Bibliotheken anbietet? bevor Sie dies überall veröffentlichen.
Martijn Pieters
@MartijnPieters Ich habe es nur auf ein paar relevante Fragen gepostet und das Projekt ist MIT-frei. Was ist also los? Vielleicht könnten Sie etwas toleranter sein.
Patotom
0
var test = [
  {id:1, test: 1},
  {id:2, test: 2},
  {id:2, test: 2}
];

var result = test.findIndex(findIndex, '2');

console.log(result);

function findIndex(object) {
  return object.id == this;
}

gibt Index 1 zurück (funktioniert nur in ES 2016)

extrem
quelle
0

Ich mag diese Methode, weil es einfach ist, sie mit jedem Wert im Objekt zu vergleichen, egal wie tief es verschachtelt ist.

 while(i<myArray.length && myArray[i].data.value!==value){
  i++; 
}
// i now hows the index value for the match. 
 console.log("Index ->",i );
Daniel Lefebvre
quelle