Underscore.js的_.map函数:跳过一个值

32

我正在尝试在一个对象数组上使用underscore.js的_.map函数,以获取每个对象的一个属性组成的数组。这是一个常见的情景,因此:

var finalArray = _.map(myArray, function(obj) {
    return obj.myProperty;
});

但在某些情况下,我需要在数组中不添加任何内容。可能是这样的:

但在某些情况下,没有需要在数组中添加任何内容。可能是这样的:

var finalArray = _.map(myArray, function(obj) {
    if (!obj.ignore) {
        return obj.myProperty;
    }
});
这将导致将一个 undefined 值推入数组中,这与根本不推送任何内容不同。
是否有一种方法使 map 函数不推送任何值,或者我需要在后处理中从 finalArray 中删除不需要的 undefined

我认为你应该考虑选择Thomas Eschemann的答案作为最佳答案,因为它只循环一次数组中的所有元素,正如“是否有一种方法使map函数不推送值”问题所要求的那样,这是这个问题的主要目标。而答案是使用reduce()代替map()。 - Jean Vincent
目前选择的答案是针对问题的第二部分“我需要对finalArray进行后处理以删除不需要的undefined吗?”。而对于这个问题的答案是:不,你不需要对finalArray进行后处理,你需要使用reduce()而不是map()来避免后处理。 - Jean Vincent
7个回答

32

在使用 _.map() 之前,您应该使用 _.filter()。

var filteredArray = _.filter(myArray,function(obj) {
     return !obj.ignore;
});

var finalArray = _.map(filteredArray, function(obj) {
    return obj.myProperty;
});

after, not before - hindmost
6
根据foucdeg描述他的问题,无需转换输入即可决定它们是否应该被排除。因此,在性能方面,事先进行过滤比后期过滤更好。 - couettos

31
您可以使用reduce函数:
myArray.reduce(function (acc, obj) {
    if (!obj.ignore) {
        acc.push(obj.myProperty);
    }
    return acc;
}, []);

或者使用lodash:

_.reduce(myArray, function (acc, obj) {
  if (!obj.ignore) {
    acc.push(obj.myProperty);
  }
  return acc;
}, []);

6
我认为这是最好的答案,因为它只按照@foucdeg的要求循环遍历所有元素一次。答案是使用reduce()而不是map()。 - Jean Vincent
1
同意这应该是被接受的答案 - 循环只执行一次。还要注意,这适用于 underscorejs,不确定为什么在这里提到了 lodash,因为 OP 正在询问 underscorejs。此外,underscore 的文档有点令人困惑:“reduce 将值列表归约为单个值。” 在这种情况下,单个值是一个数组... - BoDeX

14

只使用Underscore方法,可以以点无样式完成此操作:

var finalArray = _.chain(myArray)
    .reject('ignore')
    .pluck('myProperty')
    .value();

1
我喜欢这种方法。它非常简洁易读,而且具有纯函数式、单子思想。 - TaoPR
3
你需要在Underscore中使用.chain,并且可以简单地使用.reject('ignore')代替.reject(_.property('ignore'))。 http://jsfiddle.net/nikoshr/2gpvws1u/ - nikoshr

5

.map会将一个新值映射到数组中,您可以使用.filter来筛选该数组。FYI,您可以使用.pluck从对象中映射属性:

_.chain(myArray).filter(function(obj) { return !obj.ignore; }).pluck('myProperty').value();

您也可以像这样使用.where

_.chain(myArray).where({ignore: false}).pluck('myProperty').value();

或者:

_.pluck(_.where(myArray, {ignore: false}), 'myProperty');

3
尝试使用lodash的compact()函数,它会创建一个新数组并移除所有假值元素。因此,falsenull0""undefinedNaN等值都将被移除。 https://lodash.com/docs#compact 我正在使用它,非常简洁。

1
所以这意味着您想要对数组进行过滤,然后进行映射。为了以 underscore 的方式实现此操作,您需要将数组传递到以下流程中: myArray -> filter -> map -> finalArray。
var isIncluded = function(obj){
    return !obj.ignore
}
var takeProperty = function(obj){
    return obj.myProperty
}
var finalArray = _.map( _.filter(myArray, isIncluded), takeProperty  );

1
请注意:您可以按照@dev-null在另一个答案中提出的建议,将takeProperty替换为_.pluck函数。 - TaoPR
@foucdeg Underscore 让你思考更小的单元,而不是 一个包含多个任务的臃肿函数。鼓励你编写小的函数单元,将它们加入顺序操作中,以形成更大的处理单元。 - TaoPR

0

这里还有另一种方法。它利用了underscore中的compose函数。为什么使用compose?因为compose是由数学中的范畴论支持的。这种方法也是无点风格的。

var pluckMyProp = function(array) {
    return _.pluck(array, 'myProperty')
}

var reject = function(array) {
    return _.reject(array, function(element) {
        return element['ignore'] === true
    })
}

var finalArray = _.compose(pluckMyProp, reject)
var data = [{myProperty: 1, ignore: false}, {ignore: true}, {myProperty: 2}]


finalArray(data) //=> [1,2]

将上述内容从underscore转换为lodash,将_.pluck更改为_map,将_.compose更改为_.flowRight - mrienstra

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接