2013-07-10 10 views
10

Ho un oggetto di cartelle/file che assomiglia a questo:Underscore.js findWhere oggetti nidificati

{ 
    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' 
     } 
    } 
    } 
} 

e può andare 6-7 livelli di profondità delle cartelle avere figli.

Desidero trovare l'oggetto in cui il percorso è uguale a una stringa fornita. Indipendentemente da quanto sia profondo.

sto usando sottolineatura che fa solo livello superiore:

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

Come posso fare una profonda ricerca nidificato. Il carattere di sottolineatura ha qualcosa per questo o ho bisogno di costruire un mixin con ricorsione?

risposta

11

Questo non è il codice più bella, ma ho testato fuori e sembra funzionare il modo in cui si sta chiedendo. È impostato come un lodge/underscore mixin, ma può essere usato comunque. Uso sarebbe come questo:

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

Implementazione:

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

Il return false è lì per il lodash che si interrompe se viene trovato un valore, non è sicuro se underscore lo supporta, guardando attraverso il codice, forse restituire {} potrebbe causare l'interruzione, ma non ne sono sicuro. – dariusriggins

+0

Funziona alla grande, grazie mille! – wesbos

+0

Ottima soluzione, funziona come un fascino. Mi chiedo perché questo non sia incorporato in US/LD di default! – dbau

9

Invece di findWhere, utilizzare filter, che utilizza una funzione come predicato anziché una mappa valori-chiave. Utilizzare una funzione ricorsiva per verificare il nodo corrente e i possibili bambini. Qualcosa di simile a questo:

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); 

Modifica

Assumendo questo funziona, probabilmente vi vuole fare una funzione getRecursiveFilter(searchText). Ecco come sarebbe guardare:

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

Si noti che qui, recursiveFilter utilizza arguments.callee to call itself recursively.


Here's a working demo.

+0

E 'possibile averlo senza' subl-child.html 'hardcoded? – wesbos

+0

@Siamo sicuri, aggiungilo come un altro parametro accanto a 'searchText', immagino? Vedi qui: http://jsfiddle.net/Fy9Ej/1/ – McGarnagle

+0

Spiacente, voglio trovare l'oggetto dove percorso === stringa. Indipendentemente dal suo livello superiore o da 100 livelli di profondità. Non ci sono due corde qui. – wesbos