Loda sh: не удается выполнить фильтрацию по пользовательскому предикату, состоящему из свойства и функции соответствия - PullRequest
0 голосов
/ 02 марта 2020

loda sh _.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']

Я хочу объединить 2, преобразовав свойство соответствия в функцию соответствия, как показано в функции 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;
};

Однако он не работает должным образом ( ссылка на игровую площадку ).

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 Ответ

0 голосов
/ 02 марта 2020

Ваша проблема в том, что 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>
...