lodash 过滤 属性 array of array

lodash filter by property array of array

我有一组拥有 属性 数组 'rights' 的用户,我想过滤掉拥有特定权限的用户。我想按数组过滤,所以如果我想要所有拥有完全权限的用户 ['full'] 或拥有完全和编辑权限的用户 ['full','edit']。我对使用 lodash 还很陌生,我想我可以将一些链接在一起,但我不确定是否有更有效的方法。

这是我的笨蛋:http://plnkr.co/edit/5PCvaDJaXF4uxRowVBlK?p=preview

结果['full']:

[{
    "name": "Company1 Admin",
    "rights": [
      "full"
    ]
  },
  {
    "name": "FullRights Company1",
    "rights": [
      "full","review"
    ]
  }]

结果['full','edit']:

[{
    "name": "Company1 Admin",
    "rights": [
      "full"
    ]
  },
  {
    "name": "FullRights Company1",
    "rights": [
      "full","review"
    ]
  },
  {
    "name": "EditRights Company1",
    "rights": [
      "edit"
    ]
  }]

代码:

var users = [
      {
        "name": "Company1 Admin",
        "rights": [
          "full"
        ]
      },
      {
        "name": "FullRights Company1",
        "rights": [
          "full","review"
        ]
      },
      {
        "name": "ApproveRights Company1",
        "rights": [
          "approve","review"
        ]
      },
      {
        "name": "EditRights Company1",
        "rights": [
          "edit"
        ]
      },
      {
        "name": "ReviewRights Company1",
        "rights": [
          "review"
        ]
      },
      {
        "name": "NoRights Company1",
        "rights": [
          "none"
        ]
      }
    ];
        
var tUsers = [];
var filterRights = ['full','edit'];
_.forEach(users, function(user) {
    if (_.intersection(user.rights, filterRights).length > 0) {
      tUsers.push(user);
    }
}) ;        
        
//console.log('users', JSON.stringify(users, null, 2)); 
console.log('tUsers', JSON.stringify(tUsers, null, 2));  
        
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.10.1/lodash.min.js"></script>

来自docs

_.filter(collection, predicate, thisArg);

Arguments

  • collection (Array|Object|string): The collection to iterate over.

  • [predicate=_.identity] (Function|Object|string): The function invoked per iteration.

  • [thisArg] (*): The this binding of predicate.


当您想连接不同的处理步骤时,链接非常有用。

如果您的问题陈述是

  1. 按权利过滤
  2. 按年龄最大的人排序
  3. 拿10个

那么链接就很有意义了。

这个问题似乎主要是关于过滤的自定义逻辑。

var users = [/* Your user data here */];
function filterByRights (users, rights) {
    return _.filter(users, function (user) {
        return _.any(user.rights, function (right) {
            return _.contains(rights, right);
        });
    });
}
filterByRights(users, ['full', 'edit']); // [/*Users with full or edit rights*/]

我认为我的示例很好,因为它不依赖于条件逻辑。它使用 lodash 定义的方法,如 anycontains


性能问题

我想详细说明您对性能的担忧。这里有几点。

  • 您的问题代码正在维护自己的用户过滤机制。虽然这是一个非常好的解决方案,但您应该选择让维护 lodash 的人处理这个逻辑。他们可能花了很多时间优化如何从原始数组创建另一个数组。

  • _.any_.intersection 更有效率。 _.intersection 需要处理每个元素才能知道交集是什么。 _.any 在遇到第一个通过谓词的元素时停止,否则它会检查每个元素。这一点是次要的,因为有少量的“权利”

  • 我给出的示例可能更“lodash 标准”。您通常可以完全使用 lodash 定义的方法和 trivial 谓词进行数据转换。

我认为您 intersection() (I've never seen any performance issues with this function). Here's how I would compose an iteratee using flow() 的选择是正确的:

_.filter(users, _.flow(
    _.property('rights'), 
    _.partial(_.intersection, filterRights), 
    _.size
));

property() function gets the rights property, and passes it to intersection(). We've already partially-applied the filterRights array. Lastly, the size() function is necessary to pass a thruthy/falesy value to filter().

这是对@t3dodson 回答的更新。如果使用当前 (4.17.4) Lodash 版本,您现在应该使用以下代码片段:

function filterByRights (users, rights) {
  return _.filter(users, function (user) {
    return _.some(user.rights, function (right) {
      return _.includes(rights, right);
    });
  });
}

来自Changelog

Removed _.contains in favor of _.includes

Removed _.any in favor of _.some