2012-09-10 2 views
41

Stellen Sie sich vor, ich habe eine verschachtelte Array-Struktur.Was ist die Unterstreichung.js, die dem SELECTMany-Operator von LINQ entspricht?

var nested = [ [1], [2], [3] ]; 

Mit underscore.js, wie würde ich eine abgeflachte Array erzeugen?

In C# würden Sie Enumerable.SelectMany wie folgt verwenden:

var flattened = nested.SelectMany(item => item); 

Beachten Sie, dass das Lambda in diesem Fall direkt das verschachtelte Element auswählt, aber es könnte ein beliebiger Ausdruck gewesen.

In jQuery, dann ist es möglich, benutzen Sie einfach:

var flattened = $.map(nested, function(item) { return item; }); 

jedoch dieser Ansatz nicht map Funktion mit Unterstrich ist nicht funktioniert.

Also wie würde ich das abgeflachte Array [1, 2, 3] mit underscore.js bekommen?

+3

Verwendung _.flatten? – yngccc

+0

Sie könnten auch schreiben: _.map (geschachtelt, Funktion (Element) {return item [0];}) – Darragh

+0

@Darragh, das würde für mein spezifisches Beispiel funktionieren, aber nicht, wenn die untergeordneten Arrays mehrere Elemente enthalten. –

Antwort

35
var nested = [ [1], [2], [3] ]; 
var flattened = _.flatten(nested); 

Heresa fiddle

+0

Schön und einfach! Warum habe ich das nicht in ihrer Dokumentation gesehen?:) –

+6

Hinweis: pass shallow = true, wenn du nur eine Ebene der Verflachung willst (wie SelectMany): '_.flatten (nested, true)' –

+2

['flatten'] (https://lodash.com/docs #flatten) scheint jetzt standardmäßig nur eine Ebene zu haben; Sie haben 'flattenDeep' und' flattenDepth' hinzugefügt. – mpen

37

Wenn Sie eine etwas kompliziertere Anordnung haben, sagen ein von JSON kommen, können Sie die Vorteile des pluck Methode als auch nehmen, Extrahieren der spezifischen Eigenschaft, die Sie interessiert sind, ähnlich zu parents.SelectMany(parent => parent.Items); ist

// underscore version 
var allitems = _.flatten(_.pluck(parents, 'items')); 

allitems jetzt das Array aller Unterpunkte von den Eltern, [a,b,c,d].

Und eine JSFiddle zeigt das gleiche.


Oder, wenn Sie lodash verwenden Sie mithilfe der _.flatMap Funktion das gleiche tun kann, die für den Hinweis es seit Version 4. Cred zu Noel verfügbar ist in den Kommentaren aus.

var parents = [ 
 
    { name: 'hello', items: ['a', 'b'] }, 
 
    { name: 'world', items: ['c', 'd'] } 
 
]; 
 

 

 
// version 1 of lodash, straight up 
 
var allitems = _.flatMap(parents, 'items'); 
 
logIt('straight', allitems); 
 

 
// or by wrapping the collection first 
 
var allitems = _(parents) 
 
    .flatMap('items') 
 
    .value(); 
 
logIt('wrapped', allitems); 
 

 
// this basically does _(parents).map('items').flatten().value(); 
 

 
function logIt(wat, value) { 
 
    document.getElementById('result').innerHTML += wat + ':' + JSON.stringify(value) + '\r\n<br/>'; 
 
}
<script src="https://cdn.jsdelivr.net/lodash/4.16.6/lodash.min.js"></script> 
 
<div id="result"></div>

+1

Obwohl nicht in Unterstreichung, mit Lodash, Sie könnte von der Verwendung von 'map' und' flatten' vereinfachen, nur 'flatMap' zu verwenden, so:' _.flatMap (eltern, "items") '). – Noel

+0

Danke @Noel, ich füge es meiner Antwort hinzu. Wusste das nicht, als ich meine Antwort schrieb – Patrick

2

ich keine Methoden in lodash finden konnten, die ganz wie SelectMany arbeiten, also habe ich ein mit reinem JS:

Array.prototype.selectMany = function(fn) { 
    return Array.prototype.concat(...this.map(fn)); 
}; 

Boom.

> console.log([{a:[1,2],b:'x'},{a:[3,4],b:'y'}].selectMany(o => o.a)); 
[ 1, 2, 3, 4 ] 
+0

Wirklich? Ich habe ein funktionierendes Beispiel in meine Antwort eingefügt. Was ist falsch an dieser Lösung? – Patrick

+0

@Patrick Die Reihenfolge der Vorgänge. Es wird verwirrend, wenn verschachtelt wird: 'a.selectMany (b => b.c.selectMany (d => d.e))'. Versuchen Sie, das mit Ihrer Lösung neu zu schreiben. – mpen

3

Wir können auch Patrick's solution in eine mixin machen, so dass es wird verkettbar:

_.mixin({ 
    selectMany: function(collection, iteratee=_.identity) { 
     return _.flatten(_.map(collection, iteratee)); 
    } 
}); 

Beispiele:

let sample = [{a:[1,2],b:'x'},{a:[3,4],b:'y'}]; 

console.log(_.selectMany(sample, 'a')); // [ 1, 2, 3, 4 ] 
console.log(_.chain(sample).selectMany(o => o.a).filter(a => a % 2 === 0).map(a => a * 3).value()); // [ 6, 12 ]