Множество условий фильтра javascript
Я хочу упростить массив объектов. Предположим, что у меня есть следующий массив:
var users = [{
name: 'John',
email: '[email protected]',
age: 25,
address: 'USA'
},
{
name: 'Tom',
email: '[email protected]',
age: 35,
address: 'England'
},
{
name: 'Mark',
email: '[email protected]',
age: 28,
address: 'England'
}];
И объект фильтра:
var filter = {address: 'England', name: 'Mark'};
Например, мне нужно отфильтровать всех пользователей по адресу и имени, поэтому я прохожу через свойства объекта фильтра и проверяю его:
function filterUsers (users, filter) {
var result = [];
for (var prop in filter) {
if (filter.hasOwnProperty(prop)) {
//at the first iteration prop will be address
for (var i = 0; i < filter.length; i++) {
if (users[i][prop] === filter[prop]) {
result.push(users[i]);
}
}
}
}
return result;
}
Итак, во время первой итерации, когда prop - address
будет равно 'England'
, к результату массива будут добавлены два пользователя (с именем Tom и Mark), но на второй итерации, когда prop name
будет равно Mark
, только последний пользователь должен быть добавлен к результату массива, но в итоге я получаю два элемента в массиве.
У меня есть небольшая идея, почему это происходит, но все еще застрял на ней и не нашел хорошего решения для ее устранения. Любая помощь заметна. Спасибо.
Ответы
Ответ 1
Вы можете сделать это
var filter = {
address: 'England',
name: 'Mark'
};
var users = [{
name: 'John',
email: '[email protected]',
age: 25,
address: 'USA'
},
{
name: 'Tom',
email: '[email protected]',
age: 35,
address: 'England'
},
{
name: 'Mark',
email: '[email protected]',
age: 28,
address: 'England'
}
];
users= users.filter(function(item) {
for (var key in filter) {
if (item[key] === undefined || item[key] != filter[key])
return false;
}
return true;
});
console.log(users)
Ответ 2
Еще один вариант для тех из вас, кто любит сжатый код.
ПРИМЕЧАНИЕ: метод FILTER может принимать дополнительный аргумент this, затем, используя функцию стрелки E6, мы можем повторно использовать правильное this, чтобы получить хорошую однострочную строку.
var users = [{name: 'John',email: '[email protected]',age: 25,address: 'USA'},
{name: 'Tom',email: '[email protected]',age: 35,address: 'England'},
{name: 'Mark',email: '[email protected]',age: 28,address: 'England'}];
var query = {address: "England", name: "Mark"};
var result = users.filter(search, query);
function search(user){
return Object.keys(this).every((key) => user[key] === this[key]);
}
// |----------------------- Code for displaying results -----------------|
var element = document.getElementById('result');
function createMarkUp(data){
Object.keys(query).forEach(function(key){
var p = document.createElement('p');
p.appendChild(document.createTextNode(
key.toUpperCase() + ': ' + result[0][key]));
element.appendChild(p);
});
}
createMarkUp(result);
<div id="result"></div>
Ответ 3
Вы можете сделать это в строке
users = users.filter(obj => obj.name == filter.name && obj.address == filter.address)
Ответ 4
Также можно сделать так:
this.users = this.users.filter((item) => {
return (item.name.toString().toLowerCase().indexOf(val.toLowerCase()) > -1 ||
item.address.toLowerCase().indexOf(val.toLowerCase()) > -1 ||
item.age.toLowerCase().indexOf(val.toLowerCase()) > -1 ||
item.email.toLowerCase().indexOf(val.toLowerCase()) > -1);
})
Ответ 5
Вот ES6 версия использования функции стрелки в фильтре. Публикуем это как ответ, потому что большинство из нас в настоящее время используют ES6 и могут помочь читателям продвинуться в фильтрах, используя функции стрелок, let и const.
const filter = {
address: 'England',
name: 'Mark'
};
let users = [{
name: 'John',
email: '[email protected]',
age: 25,
address: 'USA'
},
{
name: 'Tom',
email: '[email protected]',
age: 35,
address: 'England'
},
{
name: 'Mark',
email: '[email protected]',
age: 28,
address: 'England'
}
];
users= users.filter(item => {
for (let key in filter) {
if (item[key] === undefined || item[key] != filter[key])
return false;
}
return true;
});
console.log(users)
Ответ 6
Я думаю, это может помочь.
const filters = ['a', 'b'];
const results = [
{
name: 'Result 1',
category: ['a']
},
{
name: 'Result 2',
category: ['a', 'b']
},
{
name: 'Result 3',
category: ['c', 'a', 'b', 'd']
}
];
const filteredResults = results.filter(item =>
filters
.map(val => item.category.indexOf(val))
.map(val => (val > -1 ? true : false))
.reduce((acc, cum) => acc && cum)
);
console.log(filteredResults);
Ответ 7
Если окончательность вашего кода заключается в том, чтобы получить отфильтрованного пользователя, я бы инвертировал for
для оценки user
вместо уменьшения массива результатов во время каждой итерации.
Здесь пример (непроверенный):
function filterUsers (users, filter) {
var result = [];
for (i=0;i<users.length;i++){
for (var prop in filter) {
if (users.hasOwnProperty(prop) && users[i][prop] === filter[prop]) {
result.push(users[i]);
}
}
}
return result;
}
Ответ 8
функциональное решение
function applyFilters(data, filters) {
return data.filter(item =>
Object.keys(filters)
.map(keyToFilterOn =>
item[keyToFilterOn].includes(filters[keyToFilterOn]),
)
.reduce((x, y) => x && y, true),
);
}
это должно делать работу
applyFilters(users, filter);
Ответ 9
с составом некоторых маленьких помощников:
const filter = {address: 'England', name: 'Mark'};
console.log(
users.filter(and(map(propMatches)(filter)))
)
function propMatches<T>(property: string, value: any) {
return (item: T): boolean => item[property] === value
}
function map<T>(mapper: (key: string, value: any, obj: T) => (item:T) => any) {
return (obj: T) => {
return Object.keys(obj).map((key) => {
return mapper(key, obj[key], obj)
});
}
}
export function and<T>(predicates: ((item: T) => boolean)[]) {
return (item: T) =>
predicates.reduce(
(acc: boolean, predicate: (item: T) => boolean) => {
if (acc === undefined) {
return !!predicate(item);
}
return !!predicate(item) && acc;
},
undefined // initial accumulator value
);
}
Ответ 10
Используя Array.Filter() с функциями стрелок, мы можем добиться этого, используя
users = users.filter(x => x.name == 'Mark' && x.address == 'England');
Вот полный фрагмент
// initializing list of users
var users = [{
name: 'John',
email: '[email protected]',
age: 25,
address: 'USA'
},
{
name: 'Tom',
email: '[email protected]',
age: 35,
address: 'England'
},
{
name: 'Mark',
email: '[email protected]',
age: 28,
address: 'England'
}
];
//filtering the users array and saving
//result back in users variable
users = users.filter(x => x.name == 'Mark' && x.address == 'England');
//logging out the result in console
console.log(users);
Ответ 11
const data = [{
realName: 'Sean Bean',
characterName: 'Eddard "Ned" Stark'
}, {
realName: 'Kit Harington',
characterName: 'Jon Snow'
}, {
realName: 'Peter Dinklage',
characterName: 'Tyrion Lannister'
}, {
realName: 'Lena Headey',
characterName: 'Cersei Lannister'
}, {
realName: 'Michelle Fairley',
characterName: 'Catelyn Stark'
}, {
realName: 'Nikolaj Coster-Waldau',
characterName: 'Jaime Lannister'
}, {
realName: 'Maisie Williams',
characterName: 'Arya Stark'
}];
const filterKeys = ['realName', 'characterName'];
const multiFilter = (data = [], filterKeys = [], value = '') => data.filter((item) => filterKeys.some(key => item[key].toString().toLowerCase().includes(value.toLowerCase()) && item[key]));
let filteredData = multiFilter(data, filterKeys, 'stark');
console.info(filteredData);
/* [{
"realName": "Sean Bean",
"characterName": "Eddard "Ned" Stark"
}, {
"realName": "Michelle Fairley",
"characterName": "Catelyn Stark"
}, {
"realName": "Maisie Williams",
"characterName": "Arya Stark"
}]
*/