stelle - javascript map




Aus einem Array von Objekten extrahieren Sie den Wert einer Eigenschaft als Array (7)

Ich habe JavaScript-Objekt-Array mit der folgenden Struktur:

objArray = [ { foo: 1, bar: 2}, { foo: 3, bar: 4}, { foo: 5, bar: 6} ];

Ich möchte ein Array mit den Werten des Schlüssels foo extrahieren, was zu einem Wert von [ 1, 3, 5 ] .

Ich habe dies mit dem trivialen Ansatz wie folgt erreicht:

function getFields(input, field) {
    var output = [];
    for (var i=0; i < input.length ; ++i)
        output.push(input[i][field]);
    return output;
}

var result = getFields(objArray, "foo"); // returns [ 1, 3, 5 ]

Gibt es eine elegantere und performantere Methode, um dies zu erreichen?

Hinweis zu vorgeschlagenem Duplikat , diese Frage fragt, wie ein Objekt in ein Array konvertiert werden kann. In dieser Frage wird gefragt, wie eine einzelne Eigenschaft aus einem Array von Objekten extrahiert wird.


Es hängt von Ihrer Definition von "besser" ab.

Die anderen Antworten weisen auf die Verwendung von Karten hin, die natürlich sind (besonders für Leute, die an einen funktionalen Stil gewöhnt sind) und prägnant sind. Ich empfehle dringend, es zu benutzen (wenn Sie sich nicht mit den wenigen IE8-IT-Jungs kümmern). Also, wenn "besser" bedeutet "prägnanter", "wartungsfreundlich", "verständlich" dann ja, es ist viel besser.

Auf der anderen Seite, diese Schönheit kommt nicht ohne zusätzliche Kosten. Ich bin kein großer Fan von Microbench, aber ich habe hier einen kleinen Test gemacht . Das Ergebnis ist vorhersehbar, der alte hässliche Weg scheint schneller zu sein als die Kartenfunktion. Also, wenn "besser" "schneller" bedeutet, dann nein, bleib bei der alten Schulmode.

Wieder ist dies nur eine Mikrobench und in keiner Weise befürworten gegen die Verwendung der map , es ist nur meine zwei Cent :).


Es ist besser, eine Art von Bibliotheken wie lodash oder Unterstrich für die Browser-Sicherheit zu verwenden.

In lodash können Sie die Werte einer Eigenschaft im Array mit der folgenden Methode abrufen

_.map(objArray,"foo")

und im Unterstrich

_.pluck(objArray,"foo")

beide werden zurückkehren [1, 3, 5]


Ich spreche für die JS-Einzellösungen und habe festgestellt, dass eine einfache indizierte for Schleife, so unelegant sie auch sein mag, leistungsfähiger ist als ihre Alternativen.

https://jsperf.com/extract-prop-from-object-array/

Extrahieren einer einzelnen Eigenschaft aus einem Array mit 100000 Elementen

Traditionell für die Schleife 368 Ops / Sek

var vals=[];
for(var i=0;i<testArray.length;i++){
   vals.push(testArray[i].val);
}

ES6 für ... der Schleife 303 Ops / sek

var vals=[];
for(var item of testArray){
   vals.push(item.val); 
}

Array.prototype.map 19 Ops / Sek

var vals = testArray.map(function(a) {return a.val;});

Bearbeiten: Ops / s aktualisiert 10/2017. TL; DR - .map () ist langsam. Aber manchmal ist Lesbarkeit mehr wert als Leistung.


Ja, aber es beruht auf einer ES5-Funktion von JavaScript. Dies bedeutet, dass es nicht in IE8 oder älter funktioniert.

var result = objArray.map(function(a) {return a.foo;});

Auf ES6-kompatiblen JS-Interpretern können Sie der Kürze halber eine Pfeilfunktion verwenden:

var result = objArray.map(a => a.foo);

Documentation


Verwenden von Documentation :

function getFields(input, field) {
    return input.map(function(o) {
        return o[field];
    });
}

Siehe den obigen Link für ein Shim für Pre-ES5-Browser.


Während map eine richtige Lösung ist, um 'Spalten' aus einer Liste von Objekten auszuwählen, hat sie einen Nachteil. Wenn nicht explizit überprüft wird, ob die Spalten vorhanden sind oder nicht, wird ein Fehler ausgegeben und (im besten Fall) undefined . Ich würde mich für eine reduce entscheiden, die die Eigenschaft einfach ignorieren oder sogar mit einem Standardwert einrichten kann.

function getFields(list, field) {
    //  reduce the provided list to an array only containing the requested field
    return list.reduce(function(carry, item) {
        //  check if the item is actually an object and does contain the field
        if (typeof item === 'object' && field in item) {
            carry.push(item[field]);
        }

        //  return the 'carry' (which is the list of matched field values)
        return carry;
    }, []);
}

jsbin Beispiel

Dies würde auch dann funktionieren, wenn eines der Elemente in der bereitgestellten Liste kein Objekt ist oder das Feld nicht enthält.

Es kann sogar flexibler gemacht werden, indem ein Standardwert ausgehandelt wird, sollte ein Objekt kein Objekt sein oder das Feld nicht enthalten.

function getFields(list, field, otherwise) {
    //  reduce the provided list to an array containing either the requested field or the alternative value
    return list.reduce(function(carry, item) {
        //  If item is an object and contains the field, add its value and the value of otherwise if not
        carry.push(typeof item === 'object' && field in item ? item[field] : otherwise);

        //  return the 'carry' (which is the list of matched field values)
        return carry;
    }, []);
}

jsbin Beispiel

Dies wäre bei map dasselbe, da die Länge des zurückgegebenen Arrays mit dem bereitgestellten Array übereinstimmen würde. (In diesem Fall ist eine map etwas billiger als eine reduce ):

function getFields(list, field, otherwise) {
    //  map the provided list to an array containing either the requested field or the alternative value
    return list.map(function(item) {
        //  If item is an object and contains the field, add its value and the value of otherwise if not
        return typeof item === 'object' && field in item ? item[field] : otherwise;
    }, []);
}

jsbin Beispiel

Und dann gibt es die flexibelste Lösung, mit der Sie zwischen beiden Verhaltensweisen wechseln können, indem Sie einfach einen alternativen Wert angeben.

function getFields(list, field, otherwise) {
    //  determine once whether or not to use the 'otherwise'
    var alt = typeof otherwise !== 'undefined';

    //  reduce the provided list to an array only containing the requested field
    return list.reduce(function(carry, item) {
        //  If item is an object and contains the field, add its value and the value of 'otherwise' if it was provided
        if (typeof item === 'object' && field in item) {
            carry.push(item[field]);
        }
        else if (alt) {
            carry.push(otherwise);
        }

        //  return the 'carry' (which is the list of matched field values)
        return carry;
    }, []);
}

jsbin Beispiel

Wie die obigen Beispiele (hoffentlich) ein wenig Licht in die Funktionsweise bringen, kürzen Array.concat die Funktion etwas, indem Array.concat die Array.concat Funktion verwenden.

function getFields(list, field, otherwise) {
    var alt = typeof otherwise !== 'undefined';

    return list.reduce(function(carry, item) {
        return carry.concat(typeof item === 'object' && field in item ? item[field] : (alt ? otherwise : []));
    }, []);
}

jsbin Beispiel


hier ist ein kürzerer Weg, es zu erreichen

var result = objArray.map(a => a.foo);




javascript-objects