JavaScript 过滤器数组多个条件
javascript filter array multiple conditions
我想简化一个对象数组。假设我有以下数组:
var users = [{
name: 'John',
email: 'johnson@mail.com',
age: 25,
address: 'USA'
},
{
name: 'Tom',
email: 'tom@mail.com',
age: 35,
address: 'England'
},
{
name: 'Mark',
email: 'mark@mail.com',
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
只有最后一个用户应该添加到数组结果中,但我最终在数组中有两个元素。
我对为什么会发生它有一点想法,但仍然坚持下去,找不到一个好的解决方案来修复它。任何帮助都是可观的。谢谢。
你可以这样做
var filter = {
address: 'England',
name: 'Mark'
};
var users = [{
name: 'John',
email: 'johnson@mail.com',
age: 25,
address: 'USA'
},
{
name: 'Tom',
email: 'tom@mail.com',
age: 35,
address: 'England'
},
{
name: 'Mark',
email: 'mark@mail.com',
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)
如果您知道过滤器的名称,则可以在一行中进行操作。
users = users.filter(obj => obj.name == filter.name && obj.address == filter.address)
对于那些喜欢简洁代码的人来说,这是另一个选择。
注意:FILTER 方法可以采用额外的 this 参数,然后使用 E6 箭头函数,我们可以重用正确的 this 以获得漂亮的单行代码。
var users = [{name: 'John',email: 'johnson@mail.com',age: 25,address: 'USA'},
{name: 'Tom',email: 'tom@mail.com',age: 35,address: 'England'},
{name: 'Mark',email: 'mark@mail.com',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>
这是在过滤器中使用箭头函数的 ES6 版本。将此作为答案发布,因为我们大多数人现在都在使用 ES6,并且可以帮助读者使用箭头函数、let 和 const 以高级方式进行过滤。
const filter = {
address: 'England',
name: 'Mark'
};
let users = [{
name: 'John',
email: 'johnson@mail.com',
age: 25,
address: 'USA'
},
{
name: 'Tom',
email: 'tom@mail.com',
age: 35,
address: 'England'
},
{
name: 'Mark',
email: 'mark@mail.com',
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)
users.filter(o => o.address == 'England' && o.name == 'Mark')
对于 es6 来说要好得多。 或者您可以使用 ||(或(像这样的运算符
users.filter(o => {return (o.address == 'England' || o.name == 'Mark')})
使用 Array.Filter(( 和箭头函数,我们可以通过以下方式实现这一点
users =users.filter(x => x.name == 'Mark' && x.address == 'England'(;
这是完整的代码片段
// initializing list of users
var users = [{
name: 'John',
email: 'johnson@mail.com',
age: 25,
address: 'USA'
},
{
name: 'Tom',
email: 'tom@mail.com',
age: 35,
address: 'England'
},
{
name: 'Mark',
email: 'mark@mail.com',
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);
也可以这样做:
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);
})
改进这里的好答案,以下是我的解决方案:
const rawData = [
{ name: 'John', email: 'johnson@mail.com', age: 25, address: 'USA' },
{ name: 'Tom', email: 'tom@mail.com', age: 35, address: 'England' },
{ name: 'Mark', email: 'mark@mail.com', age: 28, address: 'England' }
]
const filters = { address: 'England', age: 28 }
const filteredData = rawData.filter(i =>
Object.entries(filters).every(([k, v]) => i[k] === v)
)
这可能会有所帮助。
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.every(val => item.category.indexOf(val) > -1)
);
console.log(filteredResults);
具有 AND 条件的动态过滤器
过滤掉性别="m"的人
var people = [
{
name: 'john',
age: 10,
gender: 'm'
},
{
name: 'joseph',
age: 12,
gender: 'm'
},
{
name: 'annie',
age: 8,
gender: 'f'
}
]
var filters = {
gender: 'm'
}
var out = people.filter(person => {
return Object.keys(filters).every(filter => {
return filters[filter] === person[filter]
});
})
console.log(out)
过滤掉性别="m"和名字="约瑟夫"的人
var people = [
{
name: 'john',
age: 10,
gender: 'm'
},
{
name: 'joseph',
age: 12,
gender: 'm'
},
{
name: 'annie',
age: 8,
gender: 'f'
}
]
var filters = {
gender: 'm',
name: 'joseph'
}
var out = people.filter(person => {
return Object.keys(filters).every(filter => {
return filters[filter] === person[filter]
});
})
console.log(out)
您可以根据需要提供任意数量的过滤器。
在 lodash 中,
_.filter(users,{address: 'England', name: 'Mark'})
在 es6 中,
users.filter(o => o.address == 'England' && o.name == 'Mark')
如果将 filter 对象中的值转换为数组,您将拥有更大的灵活性:
var filter = {address: ['England'], name: ['Mark'] };
这样,您可以过滤"英格兰">或"苏格兰"之类的内容,这意味着结果可能包括英格兰和苏格兰的记录:
var filter = {address: ['England', 'Scotland'], name: ['Mark'] };
通过该设置,您的过滤功能可以是:
const applyFilter = (data, filter) => data.filter(obj =>
Object.entries(filter).every(([prop, find]) => find.includes(obj[prop]))
);
// demo
var users = [{name: 'John',email: 'johnson@mail.com',age: 25,address: 'USA'},{name: 'Tom',email: 'tom@mail.com',age: 35,address: 'England'},{name: 'Mark',email: 'mark@mail.com',age: 28,address: 'England'}];var filter = {address: ['England'], name: ['Mark'] };
var filter = {address: ['England'], name: ['Mark'] };
console.log(applyFilter(users, filter));
如果要在filter
中放置多个条件,可以使用&&
和||
运算符。
var product= Object.values(arr_products).filter(x => x.Status==status && x.email==user)
干净实用的解决方案
const combineFilters = (...filters) => (item) => {
return filters.map((filter) => filter(item)).every((x) => x === true);
};
然后你像这样使用它:
const filteredArray = arr.filter(combineFilters(filterFunc1, filterFunc2));
例如,filterFunc1 可能如下所示:
const filterFunc1 = (item) => {
return item === 1 ? true : false;
};
我们可以使用不同的运算符来提供多个条件来通过以下方式过滤数组
使用 OR (||(算子:
const orFilter = [{a:1, b: 3}, {a:1,b:2}, {a: 2, b:2}].filter(d => (d.a !== 1 || d.b !== 2))
console.log(orFilter, 'orFilter')
使用 AND (&&( 运算符:
const andFilter = [{a:1, b: 3}, {a:1,b:2}, {a: 2, b:2}].filter(d => (d.a !== 1 && d.b !== 2))
console.log(andFilter, 'andFilter')
函数解决方案
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);
我的解决方案,基于 NIKHIL C M 解决方案:
let data = [
{
key1: "valueA1",
key2: "valueA2",
key3: []
},{
key1: "valueB1",
key2: "valueB2"
key3: ["valuesB3"]
}
];
let filters = {
key1: "valueB1",
key2: "valueB2"
};
let filteredData = data.filter((item) => {
return Object.entries(filters).every(([filter, value]) => {
return item[filter] === value;
//Here i am applying a bit more logic like
//return item[filter].includes(value)
//or filter with not exactly same key name like
//return !isEmpty(item.key3)
});
});
我正在回答的一个问题被(正确(关闭,因为重复。 但我没有看到上面任何像这样的答案。 所以这里有另一个选择。
我们可以编写一个简单的函数,它接受诸如 {name: 'mike', house: 'blue'}
之类的规范,并返回一个函数,该函数将测试传递给它的值是否与所有属性匹配。 它可以像这样使用:
const where = (spec, entries = Object .entries (spec)) => (x) =>
entries .every (([k, v]) => x [k] == v)
const users = [{name: 'John', email: 'johnson@mail.com', age: 25, address: 'USA'}, {name: 'Mark', email: 'marcus@mail.com', age: 25, address: 'USA'}, {name: 'Tom', email: 'tom@mail.com', age: 35, address: 'England'}, {name: 'Mark', email: 'mark@mail.com', age: 28, address: 'England'}]
console .log ('Mark', users .filter (where ({name: 'Mark'})))
console .log ('England', users .filter (where ({address: 'England'})))
console .log ('Mark/England', users .filter (where ({name: 'Mark', address: 'England'})))
.as-console-wrapper {max-height: 100% !important; top: 0}
如果我们想将过滤包装到单个函数中,我们可以重用相同的函数,包装方式如下:
const where = (spec, entries = Object .entries (spec)) => (x) =>
entries .every (([k, v]) => x [k] == v)
const filterBy = (spec) => (xs) =>
xs .filter (where (spec))
const users = [{name: 'John', email: 'johnson@mail.com', age: 25, address: 'USA'}, {name: 'Mark', email: 'marcus@mail.com', age: 25, address: 'USA'}, {name: 'Tom', email: 'tom@mail.com', age: 35, address: 'England'}, {name: 'Mark', email: 'mark@mail.com', age: 28, address: 'England'}]
console .log ('Mark/England', filterBy ({address: "England", name: "Mark"}) (users))
.as-console-wrapper {max-height: 100% !important; top: 0}
(当然,最后的不一定是讨好的。 我们可以更改它,以便我们可以同时使用两个参数调用它。 我觉得这更灵活,但是YMMV。
将其保留为单独的函数具有以下优点:我们可以重用它,例如,find
或其他匹配情况。
这种设计与Ramda中使用where
非常相似(免责声明:我是Ramda的作者之一。 Ramda 提供了额外的灵活性,允许任意谓词而不是必须相等的值。 所以在Ramda中,你可以写这样的东西:
filter (where ({
address: equals ('England')
age: greaterThan (25)
}) (users)
这是大致相同的想法,只是更灵活一些。
如果代码的最终目的是获取过滤的用户,我会反转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;
}
包含一些小助手的组成:
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
);
}
这是一个易于理解的功能解决方案
let filtersObject = {
address: "England",
name: "Mark"
};
let users = [{
name: 'John',
email: 'johnson@mail.com',
age: 25,
address: 'USA'
},
{
name: 'Tom',
email: 'tom@mail.com',
age: 35,
address: 'England'
},
{
name: 'Mark',
email: 'mark@mail.com',
age: 28,
address: 'England'
}
];
function filterUsers(users, filtersObject) {
//Loop through all key-value pairs in filtersObject
Object.keys(filtersObject).forEach(function(key) {
//Loop through users array checking each userObject
users = users.filter(function(userObject) {
//If userObject's key:value is same as filtersObject's key:value, they stay in users array
return userObject[key] === filtersObject[key]
})
});
return users;
}
//ES6
function filterUsersES(users, filtersObject) {
for (let key in filtersObject) {
users = users.filter((userObject) => userObject[key] === filtersObject[key]);
}
return users;
}
console.log(filterUsers(users, filtersObject));
console.log(filterUsersES(users, filtersObject));
这是我想出的另一种方法,其中filteredUsers 是一个返回用户排序列表的函数。
var filtersample = {address: 'England', name: 'Mark'};
filteredUsers() {
return this.users.filter((element) => {
return element['address'].toLowerCase().match(this.filtersample['address'].toLowerCase()) || element['name'].toLowerCase().match(this.filtersample['name'].toLowerCase());
})
}
const users = [{
name: 'John',
email: 'johnson@mail.com',
age: 25,
address: 'USA'
},
{
name: 'Tom',
email: 'tom@mail.com',
age: 35,
address: 'England'
},
{
name: 'Mark',
email: 'mark@mail.com',
age: 28,
address: 'England'
}
];
const filteredUsers = users.filter(({ name, age }) => name === 'Tom' && age === 35)
console.log(filteredUsers)
使用 lodash 而不是纯 javascript
使用lodash实际上非常简单,并且非常容易添加/修改过滤器。
import _ from 'lodash';
async getUsersWithFilter(filters) {
const users = yourArrayOfSomethingReally();
// Some properties of the 'filters' object can be null or undefined, so create a new object without those undefined properties and filter by those who are defined
const filtersWithoutUndefinedValuesObject = _.omitBy(
filters,
_.isNil,
);
return _.filter(users, { ...filtersWithoutUndefinedValuesObject });
}
omitBy 函数检查您的过滤器对象并删除任何为 null 或未定义的值(如果将其取出,lodash.filter 函数将不会返回任何结果。
filter 函数将筛选出所有值与您作为第二个参数传递给函数的对象不匹配的对象(在本例中为筛选器对象(。
为什么要用这个?
好吧,假设你有这个对象:
const myFiltersObj = {
name: "Java",
age: 50
};
如果要添加另一个筛选器,只需向 myFilterObj 添加一个新属性,如下所示:
const myFiltersObj = {
name: "Java",
email: 50,
country: "HND"
};
调用getUsersWithFilter函数,它将正常工作。如果你跳过,假设对象中的name属性,getUsersWithFilter函数将按电子邮件和国家/地区过滤就好了。
请使用您提供的数据检查下面的代码片段,它将根据多列返回过滤后的数据。
var filter = {
address: 'India',
age: '27'
};
var users = [{
name: 'Nikhil',
email: 'nikhil@mail.com',
age: 27,
address: 'India'
},
{
name: 'Minal',
email: 'minal@mail.com',
age: 27,
address: 'India'
},
{
name: 'John',
email: 'johnson@mail.com',
age: 25,
address: 'USA'
},
{
name: 'Tom',
email: 'tom@mail.com',
age: 35,
address: 'England'
},
{
name: 'Mark',
email: 'mark@mail.com',
age: 28,
address: 'England'
}
];
function filterByMultipleColumns(users, columnDataToFilter) {
return users.filter(row => {
return Object.keys(columnDataToFilter).every(propertyName => row[propertyName].toString().toLowerCase().indexOf(columnDataToFilter[propertyName].toString().toLowerCase()) > -1);
})
}
var filteredData = filterByMultipleColumns(users, filter);
console.log(filteredData);
结果: [ { "name": "Nikhil", "email": "nikhil@mail.com", "age": 27, "address": "India" }, { "name": "Minal", "email": "minal@mail.com", "age": 27, "address": "India" } ]
请查看以下链接,只需进行少量更改即可使用Javascript filter array array multiple values – example
这是用于此的基本函数:
const getValue = (value) =>
typeof value === "string" ? value.toUpperCase() : value;
function filterPlainArray(array, filters) {
const filterKeys = Object.keys(filters);
return array.filter((item) => {
return filterKeys.every((key) => {
if (!filters[key].length) {
return true;
}
return filters[key].find(
(filter) => getValue(filter) === getValue(item[key])
);
});
});
}
let filters = {
color: ["yellow"], OR ["yellow", "orange"] // if you want many options
rentedOut: [true],
};
let a = filterPlainArray(data, filters);
console.log(a);
console.log(a.length);
<小时 />如果您需要范围,例如价格,那么您需要添加此功能:
function range(start, end) {
start = parseFloat(start);
end = parseFloat(end);
return new Float32Array(end - start).fill().map((d, i) => i + start);
}
现在,您的筛选器应如下所示:
let filters = {
color: [],
rentedOut: [],
miles: range(50000, 125000),
};
来源:
- 我在youtube上的视频演示如何做到这一点:https://youtu.be/3sFBhXw9cc4
- 主要文档/论坛: https://gist.github.com/jherax/f11d669ba286f21b7a2dcff69621eb72
- 链接到我的谷歌文档,其中包含有关它的所有信息以及如何过滤范围:https://docs.google.com/document/d/1Hrn8LIJ2FD1O-3a908VrJ9evKmu7-L3jstihPTq_E7I/edit#
Vue3 Pinia
我把 trincot 的答案放在 Vue 3 Pinia 上下文中:
state: () => ({
data: [{...}, {...}, ...],
filter: {address: ['England', 'Scotland'], name: ['Mark'] }
}),
getters: {
list: (state) => {
return state.data.filter(obj =>
Object.entries(state.filter).every(([prop, find]) => find.includes(obj[prop]))
);
},
}
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"
}]
*/
arr.filter((item) => {
if(condition)
{
return false;
}
return true;
});
- 为什么typeof的数组的数组的未定义值返回为“0”;未定义的“;我的条件不认为是真的
- Javascript'数组'和'循环'如何“;变量[i]”;是一个条件
- 从json数组中查找满足条件的特定元素的值
- 使用条件for循环更新数组-Javascript
- 根据条件将函数放入数组中(如果选中复选框)
- Javascript-在一个数组中搜索整个单词,并创建一个符合条件的新数组
- 根据某些条件验证用户输入,而不是将输入输入到数组中,需要最基本的解决方案
- Javascript :基于数组的条件循环
- 根据条件 JavaScript 在父级下对类似的数组项进行分组
- 比较数组并使用条件对数组列表进行排序
- 从 JSON 对象数组中获取与条件匹配的文档
- if数组元素在for循环内部有条件
- 带条件的多维数组中的javascript和数组值
- 使用restangular从json对象数组中获取具有特定条件的json对象
- 使用handlers.js模板以数组中的最后一项为条件
- 根据条件从数组中删除对象
- 根据JavaScript中的条件将对象拆分为对象数组
- 使用具有特定条件的 lodash 添加和组合对象数组中的重复项
- 根据某些条件将 JS 绑定到可观察对象内的数组元素
- 将数组的至少“N”个元素与条件列表匹配