【问题标题】:lodash: filter array of objects with a different array of objectslodash:用不同的对象数组过滤对象数组
【发布时间】:2015-07-10 18:38:13
【问题描述】:

这个问题专门针对 lodash

给定两个对象数组,用另一个数组的对象过滤一个数组的最佳方法是什么?我试图在下面提出一个场景,我这样做的方法是使用两个 .forEach 循环,但我想知道使用 lodash 是否有更好的方法来进行这种类型的过滤。


示例
对象的主要源数组是users
var users = [
  { 'user': 'barney', 'age': 36, 'active': true },
  { 'user': 'joe', 'age': 40, 'active': false },
  { 'user': 'fred', 'age': 50, 'active': false },
  { 'user': 'fred', 'age': 60, 'active': false },
  { 'user': 'fred', 'age': 70, 'active': false },
  { 'user': 'fred', 'age': 22, 'active': false },
  { 'user': 'fred', 'age': 25, 'active': false },
  { 'user': 'barney', 'age': 40, 'active': false },
  { 'user': 'pebbles', 'age': 1,  'active': true }
];

将过滤users 数组的对象数组称为others

var others = [
  { 'user': 'fred', 'age': 60 },
  { 'user': 'fred', 'age': 70},
  { 'user': 'fred', 'age': 22}
];

基于others过滤users的期望结果是:

[
  { 'user': 'fred', 'age': 60, 'active': false },
  { 'user': 'fred', 'age': 70, 'active': false },
  { 'user': 'fred', 'age': 22, 'active': false }
];

这是获得所需结果的一种方法。

var result = [];

_.forEach(users, function (n, key) {
   _.forEach(others, function (n2, key2) {
      if (n.user === n2.user && n.age === n2.age) {
         result.push(n);
      }
   });
});

console.log(result);

这里是jsbin上的例子。
http://jsbin.com/hapariviya/1/edit?html,js,console,output

【问题讨论】:

  • 您正在尝试根据用户和年龄查找重复项?
  • @CoryDanielson - 尝试根据用户和年龄属性查找匹配项。我将其称为匹配,而不是重复。
  • 有趣的是,您的原始解决方案是迄今为止最快的。我认为如果其他人有重复,它可能会产生重复,但如果你在做result.push(n) 之后return false; 应该没问题。
  • @CoryDanielson - 很高兴知道;你用什么进行性能测试?其他答案有更多的语法糖,但如果这个版本明显更快,我会继续这条路线。
  • jsperf.com/testingdiwq 我添加了更多数据,但如果您修剪others,您将开始看到您和我之间的巨大差异。但这微不足道。无论解决方案如何,这一切都很快发生。必须平衡性能与干净的代码。干净的代码通常更好,因为大多数性能问题都与 DOM 相关

标签: javascript arrays lodash


【解决方案1】:

您可以索引其他的,然后无需嵌套循环即可获得所需的结果。无论数据量如何,这应该是一个相对有效的解决方案:

// index others by "user + age"
var lookup = _.keyBy(others, function(o) { return o.user + o.age.toString() });
// find all users where "user + age" exists in index, one loop, quick lookup. no nested loops
var result = _.filter(users, function(u) {
    return lookup[u.user + u.age.toString()] !== undefined;
});

这给出了相同的结果:

[
  { 'user': 'fred', 'age': 60, 'active': false },
  { 'user': 'fred', 'age': 70, 'active': false },
  { 'user': 'fred', 'age': 22, 'active': false }
];

有趣的是,您最初的解决方案是所有这些答案中性能最高的。

http://jsperf.com/testingdiwq

这里的性能问题可以忽略不计。在大多数情况下,DOM 交互是前端的主要性能瓶颈。如果您要针对庞大的数据集运行此程序并注意到锁定,您肯定希望通过使用 for 循环而不是使用 lodash 函数迭代来进一步优化它......但您通常不会遇到那种数据JavaScript...SQL 和其他人会更好地处理它。

【讨论】:

  • 嗯,将查找字符串创建为一种“魔术字符串”会导致意外问题吗?为了论证起见,假设用户是整数,你有用户 1 和用户 11,用户 1 是 11 岁,用户 11 是 1 岁?显然这在目前的数据结构中是不现实的,但是这种格式中就不能存在这种类型的错配吗?
  • 是的,在这种情况下肯定会发生。您必须做一棵树或其他东西才能避免此类问题。但是,性能提升可以忽略不计......除非这是在非常大的数据集上执行的,但在这种情况下,您必须切换到 for 循环才能获得良好的性能。
  • 在您的魔术字符串中,您还可以在用户和年龄值之间使用分隔符,即“user11-11”,其中“-”将用户和年龄分开,以避免此类问题跨度>
  • indexBy 好像改名为 keyBy
  • 请注意,如果您可以在代码开头初始化并保留查找数组,则使用查找方法实际上可能会更快。 jsperf 仅显示慢 1% 的差异,但这很可能是因为它必须每次都创建查找数组。它实际上使该测试用例的工作量翻了一番。
【解决方案2】:

这是我能想到的更简洁的方法:

var result = _.flatten(_.map(others, function(item){
  return _.filter(users, item);
}));

编辑: 道歉 JS Bin 输出混淆了嵌套数组。

【讨论】:

  • 语法很好很短,但实际上并没有返回所需的结果。所需的结果是对象数组,而不是数组数组。这里的结果是一个数组数组。
  • 谢谢;现在返回对象。
【解决方案3】:

使用 ES6 粗箭头和 lodash 的拒绝:

const result = _.reject(users, (item) => _.find(others, { user: item.user }));

【讨论】:

    【解决方案4】:
    var result = _.flatten(_.map(others, function(other){return _.where(users, other);}));
    

    【讨论】:

      【解决方案5】:

      如果你使用的是 lodash 和 ES6 语法。

          const users = [
            { 'user': 'barney', 'age': 36, 'active': true },
            { 'user': 'joe', 'age': 40, 'active': false },
            { 'user': 'fred', 'age': 50, 'active': false },
            { 'user': 'fred', 'age': 60, 'active': false },
            { 'user': 'fred', 'age': 70, 'active': false },
            { 'user': 'fred', 'age': 22, 'active': false },
            { 'user': 'fred', 'age': 25, 'active': false },
            { 'user': 'barney', 'age': 40, 'active': false },
            { 'user': 'pebbles', 'age': 1,  'active': true }
          ];
      
          const filters = [
            { 'user': 'fred', 'age': 60, 'active': false },
            { 'user': 'fred', 'age': 70, 'active': false },
            { 'user': 'fred', 'age': 22, 'active': false }
          ];
      
      
          _.filter(users, ({user, age, active}) => {
              return _.findIndex(filters, ({user:filterUser, age:filterAge, active:filterActive}) => { return (user == filterUser && age == filterAge && active == filterActive) }) >= 0;
          })
      

      【讨论】:

        猜你喜欢
        • 2018-08-22
        • 2018-09-06
        • 1970-01-01
        • 1970-01-01
        • 2019-10-02
        • 1970-01-01
        • 1970-01-01
        • 2021-01-06
        • 2016-05-12
        相关资源
        最近更新 更多