2012-09-10 104 views
41

想象一下,我有一個嵌套的數組結構。什麼是underscore.js相當於LINQ的SelectMany運算符?

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

使用underscore.js,我將如何生成一個扁平數組?

在C#中你可以使用Enumerable.SelectMany這樣的:

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

注意,在這種情況下,lambda直接選擇嵌套的項目,但它可能是任意表達式。

在jQuery中,它可能只使用:

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

但是這種方法沒有用下劃線的map功能工作。

那麼如何使用underscore.js得到扁平數組[1, 2, 3]

+3

使用_.flatten? – yngccc

+0

你也可以這樣寫:_.map(嵌套,函數(item){return item [0];}) – Darragh

+0

@Darragh,這對我的具體示例有效,但不適用於子數組包含多個元素的情況。 –

回答

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

繼承人fiddle

+0

不錯,容易!爲什麼我沒有在他們的文檔中看到?:) –

+6

注意:pass shallow = true,如果你只想要一層扁平化(就像SelectMany一樣):'_.flatten(nested,true)' –

+2

['flatten'](https://lodash.com/docs #flatten)現在默認只能做一個級別;他們增加了「flattenDeep」和「flattenDepth」。 – mpen

37

如果你有一個稍微複雜陣列,說一個從JSON來了,你可以利用pluck方法,以及,提取你有興趣,相似的特定屬性到parents.SelectMany(parent => parent.Items);

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

allitems現在是從父母,[a,b,c,d]所有子項的數組。

JSFiddle顯示相同的事情。


或者,如果你正在使用lodash您可以通過使用_.flatMap功能,可自第4版中房諾埃爾在評論指出它做同樣的事情。

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

雖然在下劃線中不可用,但使用lodash可以簡化使用'map'和'flatten'僅使用'flatMap',就像這樣:'_.flatMap(parents,「items」)')。 – Noel

+0

謝謝@Noel,我會將它添加到我的答案中。當我寫回答 – Patrick

2

我無法找到lodash的工作很喜歡SelectMany任何方法,所以我創建了一個使用純JS:

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

繁榮。

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

真的不知道嗎?我在答案中包含了一個工作示例。該解決方案有什麼問題? – Patrick

+0

@Patrick操作順序。嵌套時會引起混淆:'a.selectMany(b => b.c.selectMany(d => d.e))''。嘗試使用您的解決方案重寫。 – mpen

3

我們也可以Patrick's solution成一個混合,使之成爲可鏈接:

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

例子:

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 ]