2016-02-01 2 views
10

Ich habe Arrays von tief verschachtelten Objekten. Ich möchte eine Funktion schreiben, um beliebige untergeordnete Objekte aus diesen Arrays zu extrahieren. In einigen Fällen sind Werte verschachtelter Eigenschaften Werte und Objekte, in anderen Fällen sind sie Arrays.Extrahieren Sie tief verschachtelte untergeordnete Objekte durch Eigenschaftsname mit lodash

Beispiele für Arrays sind unter:

[{parent: {level1: {level2: 'data'}}}] 

[{parent: {level1: [{level2: {...}}, {level2: {...}}, {level2: {...}}]}}] 

[{parent: {level1: [{level2: {level3: 'data'}}, {level2: {..}}, {level2: {..}}]}}] 

Aufruf Extraktionsfunktion auf einer solchen Anordnung in einem Array von Objekten zur Folge haben sollte, dass wir interessiert sind

Beispiele für die Funktion und die Ergebnisse aufrufen. für den Beispiel-Arrays oben:

extractChildren(source, 'level2') = [{level2: 'data'}] 

extractChildren(source, 'level2') = [{level2: {...}, level2: {...}, level2: {...}] 

extractChildren(source, 'level3') = [{level3: 'data'}] 

gibt es eine prägnante Art und Weise dies mit lodash zu erreichen oder soll ich regelmäßig mit JavaScript iterieren durch Eigenschaften?

P.S. Betrachten Sie es als Äquivalent von XPath select all nodes with the name "nodename"

+2

Sie sollte al Erläutern Sie anhand eines Beispiels, welche untergeordneten Objekte genau extrahiert werden sollen, insbesondere im Hinblick darauf, wie das Ergebnis aussehen soll, wenn ein potenzielles Ziel ein anderes potenzielles Ziel enthält. – Tomalak

+1

Mehr anzeigen, bitte. Können Sie eine erwartete Eingabe, den "Aufruf" und die erwartete Ausgabe bereitstellen? –

+0

hinzugefügt weitere Informationen – krl

Antwort

1

Ich hoffe, es hilft:

'use strict'; 

let _ = require("lodash"); 
let source = [{parent: {level1: [{level2: {level3: 'data'}}, {level2: {}}, {level2: {}}]}}]; 

function extractChildren(source, specKey) { 
    let results = []; 
    let search = function(source, specKey) { 
     _.forEach(source, function(item) { 
      if (!!item[specKey]) { 
       let obj = {}; 
       obj[specKey] = item[specKey]; 
       results.push(obj); 
       return; 
      } 

      search(item, specKey); 
     }); 
    }; 

    search(source, specKey); 
    return results; 
}; 

console.log(extractChildren(source, 'level3')); 
// [ { level3: 'data' } ] 
+0

endet mit 'Maximale Call-Stack-Größe überschritten 'mit Standard-Node.js Config und meine tatsächlichen Daten – krl

+0

Wie groß sind Ihre Daten? – Festo

+0

Bis zu 10 Ebenen tief oder so, aber nicht sehr groß (Dutzende von KB), da ich sonst Streams verwenden würde.Nimmermind.Ich muss immer noch das Problem anders an, da ich muss sammle auch einige Daten von Elternobjekten und solch eine einfache 'extractChildren' Funktion funktioniert sowieso nicht für diesen Fall. – krl

1

Von this question:

Elegant:

function find_obj_by_name(obj, key) { 
    if(!(obj instanceof Array)) return []; 

    if (key in obj) 
     return [obj[key]]; 

    return _.flatten(_.map(obj, function(v) { 
     return typeof v == "object" ? find_obj_by_name(v, key) : []; 
    }), true); 
} 

Effizient:

function find_obj_by_name(obj, key) { 
    if(!(obj instanceof Array)) return []; 

    if (key in obj) 
     return [obj[key]]; 

    var res = []; 
    _.forEach(obj, function(v) { 
     if (typeof v == "object" && (v = find_obj_by_name(v, key)).length) 
      res.push.apply(res, v); 
    }); 
    return res; 
} 
+0

Der" effiziente "kann verbessert werden indem man vanilla' forEach' anstatt '_.forEach' – vsync

+0

verwendet Ich verstehe, was ist das 'fn (v, key)'. Hast du das getestet? Was ist 'fn'? – vsync

+0

Ich sehe jetzt, du hast eine Kopie kopiert sie [antwort] (http://stackoverflow.com/a/15643385/104380), änderte es und verifizierte das Ergebnis nicht. – vsync