Я пытаюсь понять, как лучше использовать функциональное программирование для достижения чистоты кода. В идеале я бы хотел использовать для этого ramda.js
, но я открыт для любой другой функциональной библиотеки.
У меня два параметра:
emailSearchTerm
Строка[{ value: 'ACTIVE'}, { value: 'INACTIVE'}]
Массив объектовУ меня есть массив, который я хочу отфильтровать по двум параметрам, указанным выше:
[
{
email: '[email protected]',
status: 'ACTIVE'
},
{
email: '[email protected]',
status: 'INACTIVE'
},
]
Как можно использовать чистую функцию, которая использует два входа, чтобы эффективно фильтровать массив объектов?
Обновлено: Отличные дополнительные вопросы:
На данный момент я использовал частичную фильтрацию по поисковому запросу:
searchTerm ? userList.filter(user => user.email.toLowerCase()
.indexOf(searchTerm.toLowerCase()) > -1) : userList
userList представляет собой массив объектов, а моя троичная функция searchTerm ищет частичные совпадения. Моя цель - расширить эту функцию, чтобы она дополнительно принимала массив статуса »- и я хотел бы сделать это в чистом, функциональном стиле, который легко читается - что-то за пределами моего текущего уровня навыков. Подводя итог, критерии следующие:
что ты уже испробовал?
@ilrein Я обновил свой ответ в соответствии с вашими потребностями
вы можете использовать .filter
и проверить, содержит ли свойство email
строку emailSearchTerm
с функцией .includes()
, и использовать .some
(который проверяет, проходит ли хотя бы один элемент в массиве тест, реализованный предоставленной функцией) для проверки и фильтрации с помощью свойства status
.
const emailSearchTerm = '[email protected]';
const arrayCheck = [{ value: 'ACTIVE'}, { value: 'INACTIVE'}];
const userList = [
{
email: '[email protected]',
status: 'ACTIVE'
},
{
email: '[email protected]',
status: 'INACTIVE'
},
]
const pureFunction = (string, arrayCheck, data) =>
data.filter(item =>
item.email.includes(string)
&& arrayCheck.some(obj => obj.value === item.status));
console.info(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: '[email protected]',
status: 'ACTIVE'
},
{
email: '[email protected]',
status: 'INACTIVE'
}
]
const output1 = matchAnyUserStatus (emailHasAt) (userList)
const output2 = matchAnyUserStatus (emailHas123) (userList)
const output3 = matchActiveUser (emailHas123) (userList)
console.info (output1)
console.info (output2)
console.info (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: '[email protected]', status: 'ACTIVE'},
{email: '[email protected]', status: 'ACTIVE'},
{email: 'peter@gmail', status: 'INACTIVE'},
{email: '[email protected]', status: 'INACTIVE'}
];
const searchActiveUsers = search(['ACTIVE']);
const searchAllUsers = search(['ACTIVE', 'INACTIVE']);
const searchActiveSoUsers = searchActiveUsers('stackoverflow');
const searchAllGmailUsers = searchAllUsers('gmail');
console.info(searchActiveSoUsers(userList)); // john
console.info(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', '[email protected]'); //=> true
contains('ACTIVE', ['ACTIVE', 'INACTIVE']); //=> true
__
Это параметр-заполнитель для каррированных функций. Это позволяет нам позже указать параметры:
const foundInJohn = contains(__, '[email protected]');
foundInJohn('stackoverflow'); //=> true
foundInJohn('gmail'); //=> false
куда
Принимает объект функций и другой объект и возвращает истину, если свойства второго объекта возвращают истину при применении к их соответствующим функциям в первом объекте:
const soUser = where({email: contains('stackoverflow')});
soUser({email: '[email protected]'}); //=> true
soUser({email: '[email protected]'}); //=> false
фильтр
Это похоже на собственный метод фильтрации в прототипе Array.
const filterGmail = filter(contains('gmail'));
filterGmail(['[email protected]', '[email protected]']); //=> ['[email protected]']
В чем ценность
emailSearchTerm
? Какой желаемый результат? Какие все поля необходимо просмотреть? Какие критерии определяют, есть совпадение или нет?