代码之家  ›  专栏  ›  技术社区  ›  yiksanchan

Lodash:无法按同时包含匹配属性和函数的自定义谓词进行筛选

  •  0
  • yiksanchan  · 技术社区  · 4 年前

    lodash _.filter 允许按匹配属性和匹配函数进行筛选。

    提供以下数据

    var users = [
      { 'user': 'barney', 'age': 36, 'active': true },
      { 'user': 'fred',   'age': 40, 'active': false }
    ];
    

    我是说匹配属性

    _.filter(users, { 'age': 36, 'active': true });
    // => objects for ['barney']
    

    我是说匹配函数

    _.filter(users, function(o) { return !o.active; });
    // => objects for ['fred']
    

    functionPredicate 功能。

    const functionPredicate = values => {
      let funcPredicate = _.identity;
      Object.entries(values).forEach(([fieldName, fieldValue]) => {
        if (_.isFunction(fieldValue)) {
          funcPredicate = funcPredicate && fieldValue;
        } else {
          const newPredicate = item => item[fieldName] === fieldValue;
          funcPredicate = funcPredicate && newPredicate;
        }
      });
      return funcPredicate;
    };
    

    然而,它并没有像预期的那样工作( playground link ).

    const _ = require('lodash');
    
    var users = [
      { 'user': 'barney', 'age': 36, 'active': true },
      { 'user': 'fred',   'age': 40, 'active': false },
      { 'user': 'john',   'age': 40, 'active': false },
      { 'user': 'seth',   'age': 44, 'active': true },
    ];
    
    const functionPredicate = values => {
      let funcPredicate = _.identity;
      Object.entries(values).forEach(([fieldName, fieldValue]) => {
        if (_.isFunction(fieldValue)) {
          funcPredicate = funcPredicate && fieldValue;
        } else {
          const newPredicate = item => (item[fieldName] === fieldValue);
          funcPredicate = funcPredicate && newPredicate;
        }
      });
      return funcPredicate;
    };
    
    const values = {'ageFp': user => user.age > 36, 'active': true}
    const p = functionPredicate(values)
    _.filter(users, p) // wrong, it gives me both barney and seth
    // _.chain(users).filter({'active': true}).filter(user => user.age > 36).value() // correct, it gives me seth
    

    'active': true values ,它确实有效,过滤掉了巴尼。

    有人能帮我理解为什么吗?谢谢

    1 回复  |  直到 4 年前
        1
  •  0
  •   Nick Parsons Felix Kling    4 年前

    你的问题是 funcPredicate && newPredicate 不组合这两个谓词,它只返回 newPredicate && operator ). 相反,您可以创建一个包含所有谓词的数组,这些谓词必须传递才能在数组中保留项。然后对于给定的对象,检查它是否满足所有谓词(使用 _.every() ):

    const functionPredicate = values => {
      const toCheck = [];
      Object.entries(values).forEach(([fieldName, fieldValue]) => {
        if (_.isFunction(fieldValue)) {
          toCheck.push(fieldValue);
        } else {
          const newPredicate = item => item[fieldName] === fieldValue;
          toCheck.push(newPredicate);
        }
      });
      return o => _.every(toCheck, fn => fn(o));
    };
    

    _.reduce() 它允许您迭代对象键和值,如下所示:

    const users = [ { 'user': 'barney', 'age': 36, 'active': true }, { 'user': 'fred',   'age': 40, 'active': false }, { 'user': 'john',   'age': 40, 'active': false }, { 'user': 'seth',   'age': 44, 'active': true }, ];
    
    const functionPredicate = values => o => 
      _(values).reduce((acc, fieldValue, fieldName) =>
        acc.concat(_.isFunction(fieldValue) ? fieldValue : item => item[fieldName] === fieldValue), 
      _([])).every(fn => fn(o));
    
    const values = {'age': user => user.age > 36, active: true}
    const p = functionPredicate(values)
    console.log(_.filter(users, p));
    <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.min.js"></script>