50

想象一下我有一个嵌套的数组结构。

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功能。

那么如何[1, 2, 3]使用 underscore.js 获得扁平数组呢?

4

4 回答 4

44

如果你有一个稍微复杂的数组,比如来自 JSON 的数组,你也可以利用pluck方法,提取你感兴趣的特定属性,类似于parents.SelectMany(parent => parent.Items);

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

allitems现在是来自父母的所有子项的数组,[a,b,c,d].

还有一个显示相同内容的JSFiddle 。


或者,如果你使用 lodash,你可以使用_.flatMap函数来做同样的事情,该函数从版本 4 开始可用。感谢 Noel 在评论中指出它。

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) {
  console.log(wat, value)
}
<script src="https://cdn.jsdelivr.net/lodash/4.16.6/lodash.min.js"></script>
<pre id="result"></pre>


如果您想做更多的事情并且不想链接运算符,您可以使用该flow函数来获得相同的效果。如果您使用 TypeScript 并单独导入每个运算符,这很有用,因为您可以优化最终的有效负载。

const parents = [
  { name: 'hello', items: ['a', 'b'] },
  { name: 'world', items: ['c', 'd'] }
];
logIt('original', parents);

const result = _.flow(
  (collection) => _.flatMap(collection, (item) => item.items),
  (flattened) => flattened.filter((item) => item !== 'd')
)(parents);
logIt('result without "d"', result);

function logIt(wat, value) {
  console.log(wat, value);
}
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.11/lodash.min.js"></script>
<pre id="result"></pre>

于 2014-08-04T19:28:16.473 回答
42
var nested = [ [1], [2], [3] ];
var flattened = _.flatten(nested);

这是一个小提琴

于 2012-09-10T00:13:01.163 回答
3

我们还可以将Patrick 的解决方案变成一个 mixin,这样它就可以链接:

_.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 ]
于 2016-05-18T20:39:43.273 回答
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 ]
于 2016-05-05T16:50:10.790 回答