2013-07-10 8 views
10

Ich habe ein Objekt der Ordner/Dateien, die wie folgt aussieht:Underscore.js Findwhere verschachtelte Objekte

{ 
    about.html : { 
    path : './about.html' 
    }, 
    about2.html : { 
    path : './about2.html' 
    }, 
    about3.html : { 
    path : './about3.html' 
    }, 
    folderName : { 
    path : './folderName', 
    children : { 
     sub-child.html : { 
     path : 'folderName/sub-child.html' 
     } 
    } 
    } 
} 

Und es kann 6-7 Ebenen tief von Ordnern mit Kindern gehen.

Ich möchte das Objekt finden, wo Pfad ist gleich einer Zeichenfolge, die ich zur Verfügung stellen. Egal wie tief es ist.

Ich Strich verwendet, die nur Top-Level tut:

_.findWhere(files,{path:'./about2.html'} 

Wie kann ich eine tiefe, verschachtelte Suche. Hat Underscore etwas dafür oder muss ich ein Mixin mit Rekursion erstellen?

Antwort

11

Dies ist nicht der hübscheste Code ist, aber ich es getestet und es scheint so, wie Sie fragen zu arbeiten. Es ist als Lodash-/Unterstrich-Mix eingerichtet, kann aber auch verwendet werden. Nutzung würde so aussehen:

_.findDeep(testItem, { 'path': 'folderName/sub-child.html' }) 

Umsetzung:

findDeep: function(items, attrs) { 

    function match(value) { 
    for (var key in attrs) { 
     if(!_.isUndefined(value)) { 
     if (attrs[key] !== value[key]) { 
      return false; 
     } 
     } 
    } 

    return true; 
    } 

    function traverse(value) { 
    var result; 

    _.forEach(value, function (val) { 
     if (match(val)) { 
     result = val; 
     return false; 
     } 

     if (_.isObject(val) || _.isArray(val)) { 
     result = traverse(val); 
     } 

     if (result) { 
     return false; 
     } 
    }); 

    return result; 
    } 

    return traverse(items); 

} 
+0

Die Rückgabe false ist da, wenn lodash aus der Schleife ausbricht, wenn ein Wert gefunden wird, nicht sicher, ob Unterstreichung das unterstützt, durch den Code zu schauen, vielleicht {} würde es ausbrechen lassen, aber ich bin mir nicht sicher. – dariusriggins

+0

Funktioniert gut, danke eine Tonne! – wesbos

+0

Große Lösung, wirkt wie ein Charme. Ich frage mich, warum dies standardmäßig nicht in US/LD eingebaut ist! – dbau

9

Verwenden Sie anstelle von findWherefilter, die eine Funktion als Prädikat anstelle einer Schlüssel/Wert-Zuordnung verwendet. Verwenden Sie eine rekursive Funktion, um den aktuellen Knoten und mögliche Kinder zu überprüfen. Etwas wie folgt aus:

var searchText = './about2.html'; 

var recursiveFilter = function(x) { 
    return x.path == searchText || 
     (typeof x.children != 'undefined' && recursiveFilter(x.children['sub-child.html'])); 
}; 

_.filter(files, recursiveFilter); 

bearbeiten

Unter der Annahme, das funktioniert, werden Sie wahrscheinlich wollen eine Funktion getRecursiveFilter(searchText) machen. Hier ist, wie das aussehen würde:

function getRecursiveFilter(searchText) { 
    var recursiveFilter = function(x) { 
     return x.path == searchText || 
      (typeof x.children != 'undefined' 
       && arguments.callee(x.children['sub-child.html'])); 
    }; 
    return recursiveFilter; 
} 

Hinweis darauf, dass hier recursiveFilterarguments.callee to call itself recursively verwendet.


Here's a working demo.

+0

Ist es möglich, es ohne die 'subl-child.html' hardcoded zu haben? – wesbos

+0

@We sicher, fügen Sie es einfach als einen anderen Parameter neben 'searchText', denke ich? Siehe hier: http://jsfiddle.net/Fy9Ej/1/ – McGarnagle

+0

Sorry, ich möchte das Objekt finden, wo Pfad === Zeichenfolge. Unabhängig von seiner obersten Ebene oder 100 Ebenen tief. Es gibt hier keine zwei Saiten. – wesbos