Фильтрация массива объектов строкой + массивом строк

Я пытаюсь понять, как лучше использовать функциональное программирование для достижения чистоты кода. В идеале я бы хотел использовать для этого ramda.js, но я открыт для любой другой функциональной библиотеки.

У меня два параметра:

  1. emailSearchTerm Строка
  2. [{ value: 'ACTIVE'}, { value: 'INACTIVE'}] Массив объектов

У меня есть массив, который я хочу отфильтровать по двум параметрам, указанным выше:

[
  {
    email: '123@example.com',
    status: 'ACTIVE'
  },
  {
    email: '1234@stackoverflow.com',
    status: 'INACTIVE'
  },
]

Как можно использовать чистую функцию, которая использует два входа, чтобы эффективно фильтровать массив объектов?

Обновлено: Отличные дополнительные вопросы:

На данный момент я использовал частичную фильтрацию по поисковому запросу:

searchTerm ? userList.filter(user => user.email.toLowerCase()
    .indexOf(searchTerm.toLowerCase()) > -1) : userList

userList представляет собой массив объектов, а моя троичная функция searchTerm ищет частичные совпадения. Моя цель - расширить эту функцию, чтобы она дополнительно принимала массив статуса »- и я хотел бы сделать это в чистом, функциональном стиле, который легко читается - что-то за пределами моего текущего уровня навыков. Подводя итог, критерии следующие:

  1. Частичное совпадение посредством ввода электронной почты со свойством электронной почты в userList
  2. Полное совпадение по статусу
  3. оба параметра должны быть удовлетворены

В чем ценность emailSearchTerm? Какой желаемый результат? Какие все поля необходимо просмотреть? Какие критерии определяют, есть совпадение или нет?

Nikhil Aggarwal 31.10.2018 13:56

что ты уже испробовал?

Scott Sauyet 31.10.2018 13:57

@ilrein Я обновил свой ответ в соответствии с вашими потребностями

Artyom Amiryan 31.10.2018 17:11
1
3
1 174
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

вы можете использовать .filter и проверить, содержит ли свойство email строку emailSearchTerm с функцией .includes(), и использовать .some (который проверяет, проходит ли хотя бы один элемент в массиве тест, реализованный предоставленной функцией) для проверки и фильтрации с помощью свойства status.

const emailSearchTerm = '123@example.com';
const arrayCheck = [{ value: 'ACTIVE'}, { value: 'INACTIVE'}];

const userList = [
  {
    email: '123@example.com',
    status: 'ACTIVE'
  },
  {
    email: '1234@stackoverflow.com',
    status: 'INACTIVE'
  },
]

const pureFunction = (string, arrayCheck, data) =>
   data.filter(item =>
      item.email.includes(string)
      && arrayCheck.some(obj => obj.value === item.status));

console.log(pureFunction(emailSearchTerm, arrayCheck, userList));

РЕДАКТИРОВАТЬ

мой код был обновлен, я добавил функционал фильтра в чистую функцию, чтобы вы могли использовать его как чистую функцию с теми же типами данных, что и сейчас

Вот возможный подход с использованием ванильного JavaScript.

Я пользуюсь каррированием и частичным применением. Проверьте, какое совпадение электронной почты может быть любым сопоставитель. Я предоставляю partialMatch, но вы можете реализовать любые функции для получения более сложных сопоставителей.

const equals = x => y => x === y

const contains = xs => x => 
     xs.some (equals (x))
     
const partialMatch = x => y => y.toLowerCase().indexOf (x.toLowerCase()) > -1

// Note that turning that array of objects with  { value: '[STATUS]' }
// should be transformed to an array of string to make things simpler!
const anyStatus = contains (['ACTIVE', 'INACTIVE'])
const activeStatus = contains (['ACTIVE'])

const matchUser = containsStatus => emailMatcher => userList =>
      userList.filter (({ email, status }) =>
          emailMatcher (email)
          && containsStatus (status)
      )

const matchAnyUserStatus = matchUser (anyStatus)
const matchActiveUser = matchUser (activeStatus)

const emailHasAt = partialMatch ('@')
const emailHas123 = partialMatch ('123')

const userList = [{
    email: '123@example.com',
    status: 'ACTIVE'
  },
  {
    email: '1234@stackoverflow.com',
    status: 'INACTIVE'
  }
]

const output1 = matchAnyUserStatus (emailHasAt) (userList)
const output2 = matchAnyUserStatus (emailHas123) (userList)
const output3 = matchActiveUser (emailHas123) (userList)

console.log (output1)
console.log (output2)
console.log (output3)

Вот решение с использованием Рамда:

const {curry, contains, __, where, filter} = R; // Ramda

const search = curry(function (statuses, emailMatch, list) {
  const email = contains(emailMatch);
  const status = contains(__, statuses);
  return filter(where({email, status}), list);
});

const userList = [
  {email: 'john@stackoverflow.com', status: 'ACTIVE'},
  {email: 'david@gmail.com', status: 'ACTIVE'},
  {email: 'peter@gmail', status: 'INACTIVE'},
  {email: 'tom@stackoverflow.com', status: 'INACTIVE'}
];

const searchActiveUsers = search(['ACTIVE']);
const searchAllUsers = search(['ACTIVE', 'INACTIVE']);
const searchActiveSoUsers = searchActiveUsers('stackoverflow');
const searchAllGmailUsers = searchAllUsers('gmail');

console.log(searchActiveSoUsers(userList)); // john
console.log(searchAllGmailUsers(userList)); // david & peter
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.min.js"></script>

Быстрое объяснение:

карри

Принимает функцию и возвращает функцию, которая продолжает возвращать функцию до тех пор, пока не будут предоставлены все параметры. Пример:

const sum = curry((a, b, c) => a + b + c);
sum(10)(20)(30); //=> 60
sum(10, 20)(30); //=> 60
sum(10, 20, 30); //=> 60

Это позволяет вам создавать функции, связанные с определенными параметрами:

const searchActiveUsers = search(['ACTIVE']);
const searchActiveSoUsers = searchActiveUsers('stackoverflow');
searchActiveSoUsers(userList); // john

содержит

Принимает значение и список и возвращает истину, если значение найдено в списке: (В Ramda строки и массивы являются списками.)

contains('stackoverflow.com', 'john@stackoverflow.com'); //=> true
contains('ACTIVE', ['ACTIVE', 'INACTIVE']); //=> true

__

Это параметр-заполнитель для каррированных функций. Это позволяет нам позже указать параметры:

const foundInJohn = contains(__, 'john@stackoverflow.com');
foundInJohn('stackoverflow'); //=> true
foundInJohn('gmail'); //=> false

куда

Принимает объект функций и другой объект и возвращает истину, если свойства второго объекта возвращают истину при применении к их соответствующим функциям в первом объекте:

const soUser = where({email: contains('stackoverflow')});
soUser({email: 'john@stackoverflow.com'}); //=> true
soUser({email: 'david@gmail.com'}); //=> false

фильтр

Это похоже на собственный метод фильтрации в прототипе Array.

const filterGmail = filter(contains('gmail'));
filterGmail(['david@gmail.com', 'john@stackoverflow.com']); //=> ['david@gmail.com']

Другие вопросы по теме