Ruft den Index des Objekts in einem Array ab, der einer Bedingung entspricht

318

Ich habe ein Array wie dieses:

[{prop1:"abc",prop2:"qwe"},{prop1:"bnmb",prop2:"yutu"},{prop1:"zxvz",prop2:"qwrq"},...]

Wie kann ich den Index des Objekts abrufen, der einer Bedingung entspricht, ohne das gesamte Array zu durchlaufen?

Zum Beispiel prop2=="yutu"möchte ich einen Index erhalten 1.

Ich habe gesehen, .indexOf()aber ich denke, es wird für einfache Arrays wie verwendet ["a1","a2",...]. Ich habe auch überprüft, $.grep()aber dies gibt Objekte zurück, nicht den Index.

Ampere
quelle

Antworten:

729

Ab 2016 sollten Sie hierfür Array.findIndex(einen ES2015 / ES6-Standard) verwenden:

a = [
  {prop1:"abc",prop2:"qwe"},
  {prop1:"bnmb",prop2:"yutu"},
  {prop1:"zxvz",prop2:"qwrq"}];
    
index = a.findIndex(x => x.prop2 ==="yutu");

console.log(index);

Es wird in Google Chrome, Firefox und Edge unterstützt. Für Internet Explorer befindet sich auf der verknüpften Seite eine Polyfüllung.

Leistungshinweis

Funktionsaufrufe sind teuer, daher funktioniert eine einfache Schleife bei wirklich großen Arrays viel besser als findIndex:

let test = [];

for (let i = 0; i < 1e6; i++)
    test.push({prop: i});


let search = test.length - 1;
let count = 100;

console.time('findIndex/predefined function');
    let fn = obj => obj.prop === search;

    for (let i = 0; i < count; i++)
        test.findIndex(fn);
console.timeEnd('findIndex/predefined function');


console.time('findIndex/dynamic function');
    for (let i = 0; i < count; i++)
        test.findIndex(obj => obj.prop === search);
console.timeEnd('findIndex/dynamic function');


console.time('loop');
    for (let i = 0; i < count; i++) {
        for (let index = 0; index < test.length; index++) {
            if (test[index].prop === search) {
                break;
            }
        }
    }
console.timeEnd('loop');

Wie bei den meisten Optimierungen sollte dies mit Vorsicht und nur dann angewendet werden, wenn es tatsächlich benötigt wird.

Georg
quelle
3
Ich sehe hier keine Notwendigkeit für ein temporäres Array. Verwenden Sie einfach die Tatsache, dass die Iteratorfunktion über dem Kontext geschlossen wird, und verwenden Sie eine Variable. Außerdem funktioniert die Nicht-jQuery-Version nicht (angenommen, sie befindet sich im Index 0?). Beide Lösungen mehr tun Iteration als erforderlich, was weniger ist als ideal , wenn das Array groß ist (obwohl die Chancen , es so groß ein Mensch würde bemerken niedrig sind, es sei denn , Lookups eine geschehen viel ).
TJ Crowder
@ thg435: Ich denke immer noch, es ist eine Art Rube Goldberg-Maschine, bei der ein einfacher Hebel den Trick machen würde. :-) Aber hey, es funktioniert!
TJ Crowder
4
Können Sie bitte erklären, wie x => x.prop2=="yutu"mit findIndex () funktioniert?
Abhay Pai
4
@AbhayPai: Es ist das gleiche wiefunction(x) { return x.prop2=="yutu" }
Georg
6
Ich mag den Vorschlag, die Polyfüllung zu verwenden. Der geschriebene Code schlägt jedoch auch mit der Polyfüllung aufgrund der Verwendung einer Pfeil- / Lambda-Funktion in IE11 fehl. Neu geschrieben , wie index = a.findIndex(function (x) { return x.prop2 == "yutu" })das Problem behoben , so dass mit dem polyfill Code, Find in IE11 arbeitete
Rick Glos
26

Wie kann ich den Index des Objekts ermitteln, der einer Bedingung entspricht (ohne entlang des Arrays zu iterieren)?

Sie können nicht, etwas muss das Array durchlaufen (mindestens einmal).

Wenn sich die Bedingung stark ändert, müssen Sie die darin enthaltenen Objekte durchlaufen und überprüfen, ob sie mit der Bedingung übereinstimmen. Auf einem System mit ES5-Funktionen (oder wenn Sie einen Shim installieren) kann diese Iteration jedoch ziemlich präzise durchgeführt werden:

var index;
yourArray.some(function(entry, i) {
    if (entry.prop2 == "yutu") {
        index = i;
        return true;
    }
});

Dabei wird die neue (ish) Array#someFunktion verwendet , die die Einträge im Array durchläuft, bis die von Ihnen angegebene Funktion true zurückgibt. Die Funktion, die ich ihm gegeben habe, speichert den Index des übereinstimmenden Eintrags und kehrt dann zurück true, um die Iteration zu stoppen.

Oder verwenden Sie einfach eine forSchleife. Ihre verschiedenen Iterationsoptionen werden in dieser anderen Antwort behandelt .

Wenn Sie jedoch immer dieselbe Eigenschaft für diese Suche verwenden und die Eigenschaftswerte eindeutig sind, können Sie nur eine Schleife ausführen und ein Objekt erstellen, um sie zuzuordnen:

var prop2map = {};
yourArray.forEach(function(entry) {
    prop2map[entry.prop2] = entry;
});

(Oder Sie können eine forSchleife oder eine Ihrer anderen Optionen verwenden .)

Wenn Sie dann den Eintrag mit prop2 = "yutu"finden müssen, können Sie dies tun:

var entry = prop2map["yutu"];

Ich nenne das "Cross-Indexing" das Array. Wenn Sie Einträge entfernen oder hinzufügen (oder deren prop2Werte ändern ), müssen Sie natürlich auch Ihr Zuordnungsobjekt aktualisieren.

TJ Crowder
quelle
Danke für die Erklärung! Die Lösung mit jQuery zeigte, thg435was ich wollte ...
Amp
21

Was TJ Crowder gesagt hat, wird immer eine Art versteckte Iteration haben, mit lodash wird dies:

var index = _.findIndex(array, {prop2: 'yutu'})
aliak
quelle
1
Während Sie einfach verschiedene Möglichkeiten durchlaufen können, um den Index zu erhalten, ist Find Index die beste Lösung, die sogar in ES6 in native Array-Methoden übernommen wurde
Kelly Milligan,
13
var CarId = 23;

//x.VehicleId property to match in the object array
var carIndex = CarsList.map(function (x) { return x.VehicleId; }).indexOf(CarId);

Und für grundlegende Array-Nummern können Sie auch Folgendes tun:

var numberList = [100,200,300,400,500];
var index = numberList.indexOf(200); // 1

Sie erhalten -1, wenn im Array kein Wert gefunden werden kann.

David Castro
quelle
11
var index;
yourArray.some(function (elem, i) {
    return elem.prop2 === 'yutu' ? (index = i, true) : false;
});

Durchlaufen Sie alle Elemente des Arrays. Es gibt entweder den Index und true oder false zurück, wenn die Bedingung nicht übereinstimmt.

Wichtig ist der explizite Rückgabewert von true (oder ein Wert, dessen boolesches Ergebnis true ist). Die einzelne Zuweisung ist aufgrund eines möglichen Index mit 0 (Boolean (0) === false) nicht ausreichend, was keinen Fehler zur Folge hätte, aber die Unterbrechung der Iteration deaktiviert.

Bearbeiten

Eine noch kürzere Version der oben genannten:

yourArray.some(function (elem, i) {
    return elem.prop2 === 'yutu' && ~(index = i);
});
Nina Scholz
quelle
Was macht ~ Charakter in Ihrem zweiten Snippet?
Serkan
@serkan, es ist ein bitweiser NICHT-| Operator, es ist eine Kurzversion, um aus einem Index (mit -1) ein wahrheitsgemäßes / falsches Ergebnis zu erhalten, wenn ein Index vorhanden ist.
Nina Scholz
danke Nina, ohne das ~ Zeichen funktioniert der Code so wie er ist, nicht wahr?
Serkan
@serkan, deine Frage ist nicht klar, aber ohne ~funktioniert es nicht so.
Nina Scholz
1
Oh, !!(index = 0)und !!~(index = 0)Unterschied in der Tat. Vielen Dank!
Serkan
4

Sie können Array.prototype.some () folgendermaßen verwenden (wie in den anderen Antworten erwähnt):

https://jsfiddle.net/h1d69exj/2/

function findIndexInData(data, property, value) {
    var result = -1;
    data.some(function (item, i) {
        if (item[property] === value) {
            result = i;
            return true;
        }
    });
    return result;
}
var data = [{prop1:"abc",prop2:"qwe"},{prop1:"bnmb",prop2:"yutu"},{prop1:"zxvz",prop2:"qwrq"}]



alert(findIndexInData(data, 'prop2', "yutu")); // shows index of 1
GibboK
quelle
4

Ich habe oben viele Lösungen gesehen.

Hier verwende ich die Kartenfunktion, um den Index des Suchtextes in einem Array-Objekt zu finden.

Ich werde meine Antwort anhand der Schülerdaten erklären.

  • Schritt 1 : Erstellen Sie ein Array-Objekt für die Schüler (optional können Sie Ihr eigenes Array-Objekt erstellen).
    var students = [{name:"Rambabu",htno:"1245"},{name:"Divya",htno:"1246"},{name:"poojitha",htno:"1247"},{name:"magitha",htno:"1248"}];

  • Schritt 2 : Erstellen Sie eine Variable zum Suchen von Text
    var studentNameToSearch = "Divya";

  • Schritt 3 : Erstellen Sie eine Variable zum Speichern des übereinstimmenden Index (hier verwenden wir die Kartenfunktion zum Iterieren).
    var matchedIndex = students.map(function (obj) { return obj.name; }).indexOf(studentNameToSearch);

var students = [{name:"Rambabu",htno:"1245"},{name:"Divya",htno:"1246"},{name:"poojitha",htno:"1247"},{name:"magitha",htno:"1248"}];

var studentNameToSearch = "Divya";

var matchedIndex = students.map(function (obj) { return obj.name; }).indexOf(studentNameToSearch);

console.log(matchedIndex);

alert("Your search name index in array is:"+matchedIndex)

Rambabu Bommisetti
quelle
3
function findIndexByKeyValue(_array, key, value) {
    for (var i = 0; i < _array.length; i++) { 
        if (_array[i][key] == value) {
            return i;
        }
    }
    return -1;
}
var a = [
    {prop1:"abc",prop2:"qwe"},
    {prop1:"bnmb",prop2:"yutu"},
    {prop1:"zxvz",prop2:"qwrq"}];
var index = findIndexByKeyValue(a, 'prop2', 'yutu');
console.log(index);
Pranabesh Chand
quelle
1

Warum möchten Sie nicht genau iterieren? Die neuen Array.prototype.forEach eignen sich hervorragend für diesen Zweck!

Sie können einen binären Suchbaum verwenden, um über einen einzelnen Methodenaufruf zu suchen, wenn Sie möchten. Dies ist eine nette Implementierung von BTree und Red Black Search Tree in JS - https://github.com/vadimg/js_bintrees - aber ich bin nicht sicher, ob Sie den Index gleichzeitig finden können.

Rishabh
quelle
1

Ein Schritt mit Array.reduce () - keine jQuery

var items = [{id: 331}, {id: 220}, {id: 872}];

var searchIndexForId = 220;
var index = items.reduce(function(searchIndex, item, index){
  if(item.id === searchIndexForId) { 
    console.log('found!');
    searchIndex = index;
  }
  return searchIndex;
}, null);

wird zurückgegeben, nullwenn der Index nicht gefunden wurde.

SagiSergeNadir
quelle
0
var list =  [
                {prop1:"abc",prop2:"qwe"},
                {prop1:"bnmb",prop2:"yutu"},
                {prop1:"zxvz",prop2:"qwrq"}
            ];

var findProp = p => {
    var index = -1;
    $.each(list, (i, o) => {
        if(o.prop2 == p) {
            index = i;
            return false; // break
        }
    });
    return index; // -1 == not found, else == index
}
Ruben Morales Felix
quelle
0

Georg hat bereits erwähnt, dass ES6 Array.findIndex dafür hat. Einige andere Antworten können mit der Array.some-Methode für ES5 umgangen werden.

Ein eleganterer Ansatz kann sein

var index;
for(index = yourArray.length; index-- > 0 && yourArray[index].prop2 !== "yutu";);

Gleichzeitig möchte ich betonen, dass Array.some mit binären oder anderen effizienten Suchtechniken implementiert werden kann. In einigen Browsern ist die for-Schleife möglicherweise besser.

Sanjoy
quelle
0

Versuchen Sie diesen Code

var x = [{prop1:"abc",prop2:"qwe"},{prop1:"bnmb",prop2:"yutu"},{prop1:"zxvz",prop2:"qwrq"}]
let index = x.findIndex(x => x.prop1 === 'zxvz')
Trilok Singh
quelle