Фильтрация массива объектов с помощью строки + массива строк - PullRequest
0 голосов
/ 31 октября 2018

Я пытаюсь понять, как лучше использовать функциональное программирование для достижения чистоты кода. В идеале я хотел бы использовать 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. оба параметра должны быть удовлетворены

Ответы [ 3 ]

0 голосов
/ 31 октября 2018

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

Я пользуюсь карри и частичным применением. Проверьте, насколько совпадает электронная почта, может быть matcher . Я предоставляю 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)
0 голосов
/ 06 ноября 2018

Вот решение, использующее Рамда :

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

содержит

Принимает значение и список и возвращает true, если значение найдено в списке: (В 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

, где

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

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']
0 голосов
/ 31 октября 2018

вы можете использовать .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));

EDIT

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

...