如何使用Underscore.js过滤对象?

11

我有一个这样的对象:

> Object
  > Rett@site.com: Array[100]
  > pel4@gmail.com: Array[4]
    > 0
       id : 132
       selected : true
    > 1
       id : 51
       selected : false

如何使用下划线 _.filter() 来返回只包含选项为 true 的项?

我从未有过通过 _.filter() 深入到层级的需求。类似以下代码:

var stuff = _.filter(me.collections, function(item) {
    return item[0].selected === true;
});

感谢你


你能澄清一下对象格式吗?它看起来像是以电子邮件地址为键的数组哈希表? - rjz
没错,我该怎么解释? - AnApprentice
你正在尝试从哈希中取出项,其中所有数组元素都具有selected == true的属性? - rjz
只返回选中项为 true 的正确项目。 - AnApprentice
好的,我还不太确定你在寻找什么,但是我已经发布了两种最有可能的情况的策略:^) - rjz
6个回答

10
如果您想从任何电子邮件地址中提取所有selectedtrue的数组元素,可以像这样进行迭代:
var selected = [];

for (email in emailLists) {
    selected.concat(_.filter(emailLists[email], function (item) {
        return item.selected === true;
    }));
}

如果你只想提取其中所有元素都为 selected 的数组,你可以尝试像这样操作:

var stuff = _.filter(me.collections, function(item) {
    return _.all(item, function (jtem) { 
        jtem.selected === true;
    });
});

奇怪,我得到了一个“未捕获的语法错误:意外的标识符” - AnApprentice
不应该使用 for..in 来迭代数组,特别是在需要保持索引顺序的情况下。 - Mulan
这将我的对象转换为数组。 - chovy
@chovy 如果你需要一个对象,你可以将你的对象转换为一个由["key", "value"]对组成的数组,应用过滤器,然后使用_.object将结果压缩起来。 - rjz
Underscore提供了一种名为迭代器简写的方法,它允许您传递一个形如{selected: true}的对象,而不是内部函数return item.selected === true - Julian
显示剩余4条评论

5

Underscore的filter方法可以用于作为哈希表或字典使用的对象,但它将返回该对象可枚举值的数组,并剥离键。我需要一个函数来按其值过滤哈希表并保留键,于是我用Coffeescript写了这个:

hash_filter: (hash, test_function) ->
  keys = Object.keys hash

  filtered = {}
  for key in keys
    filtered[key] = hash[key] if test_function hash[key]
  filtered

如果您没有使用Coffeescript,这里是一些经过清理的Javascript编译结果:

hash_filter = function(hash, test_function) {
  var filtered, key, keys, i;
  keys = Object.keys(hash);
  filtered = {};
  for (i = 0; i < keys.length; i++) {
    key = keys[i];
    if (test_function(hash[key])) {
      filtered[key] = hash[key];
    }
  }
  return filtered;
}


hash = {a: 1, b: 2, c: 3};
console.log((hash_filter(hash, function(item){return item > 1;})));
// Object {b=2, c=3}

TL; DR: Object.keys() 非常好用!

我把关键字作为第二个参数添加进去了,就像Underscore的_.filter()函数一样。希望这样做可以!:) - Matt Fletcher
_.filter for object with keys is just _.pick - oriadam

1
const obj = {
    1 : { active: true },
    2 : { active: false },
    3 : { active: false },
}

let filtered = Object.entries(obj).reduce((acc, current) => {
    const currentEntry = current[1];
    const currentKey = current[0];
    //here you check condition
    if (currentEntry.active) {
      return {
        ...acc,
        [currentKey]: currentEntry
      }
    }
    return acc;
}, {})

有一个经验法则,如果你需要实现一些非常奇特的东西,请查阅reducer,它可以解决几乎所有与对象相关的问题,使用起来有点棘手,但相信我,仔细阅读文档会得到回报。


1
@Dexygen使用_.pick是正确的,但是有一种更简洁的解决方案,因为该函数还接受一个谓词。

返回对象的副本,仅过滤允许的键(或有效键数组)的值。 或者接受指示要选择哪些键的谓词

(强调是我的)

这是我在项目中使用的一个真实例子。

_.pick({red: false, yellow: true, green: true}, function(value, key, object) {
    return value === true;
});
// {yellow: true, green: true}

1
我有一个名为allFilterValues的对象,包含以下内容:
{"originDivision":"GFC","originSubdivision":"","destinationDivision":"","destinationSubdivision":""}

这样做虽然有些丑陋,但是你要求基于下划线的方式来过滤对象。以下是我返回仅具有非falsy值的筛选元素的方法; 你可以将筛选器的返回语句切换为任何你需要的内容:

    var nonEmptyFilters = _.pick.apply({}, [allFilterValues].concat(_.filter(_.keys(allFilterValues), function(key) {
        return allFilterValues[key];
    })));

输出(JSON / 字符串化):

{"originDivision":"GFC"}

-1
也许你想要一种最简单的方法
_.filter(me.collections, { selected: true})

这个答案部分正确;你可以在Underscore中使用{selected: true}作为谓词,例如与_.filter_.some一起使用。但在这种情况下,这并不是全部的故事,因为带有{selected: true}的对象嵌入在一个更大的对象中。 - Julian

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