强调在有多个参数时如何过滤所有对象 [英] underscore how to filter all objects when there are multiple parameters
问题描述
当我从页面上的过滤器传递一个或多个值时,我有一个问题如何正确过滤数据.例如,我有一个带有数据的对象:
I have a problem how to correctly filter data when it I pass one or several values from filters on the page. For example I have such object with data:
let data = [
{'name': 'test 1', 'address': 'New York', 'class_id': [1, 2, 3], 'country': 'USA', 'country_id': 20},
{'name': 'test 2', 'address': 'Lisbona', 'class_id': [2, 3], 'country': 'Portugal', 'country_id': 12},
{'name': 'test 3', 'address': 'New York', 'class_id': [2], 'country': 'USA', 'country_id': 20},
{'name': 'test 4', 'address': 'Atlanta', 'class_id': [2], 'country': 'USA', 'country_id': 20},
{'name': 'test 5', 'address': 'New York', 'class_id': [3], 'country': 'USA', 'country_id': 20},
{'name': 'test 6', 'address': 'Rio', 'class_id': [1], 'country': 'Brazil', 'country_id': 11},
]
当我传递一个值时,我想过滤特定的数据,使其看起来像class_id,例如:[3]
I would like to filter specific data when I pass eg one value so that it looks in class_id eg: [3]
但是我也想过滤所有满足更多条件的对象,即当class_id:[3]和country_id:20时过滤掉
but I would also like to filter all objects that meet more conditions, i.e., filter out when class_id: [3] and country_id: 20
使结果返回以下结果
data = [
{'name': 'test 1', 'address': 'New York', 'class_id': [1, 2, 3], 'country': 'USA', 'country_id': 20},
{'name': 'test 5', 'address': 'New York', 'class_id': [3], 'country': 'USA', 'country_id': 20},
]
我尝试使用_.where解决方案无济于事.我还尝试了_.filter和_.contains,它仅在我搜索class_id之后才起作用,但是如果我在过滤器中给出了第二个条件,即country_id,那么不幸的是,什么也没有返回
I tried solutions using _.where did not help. I also tried with _.filter and _.contains, it works only if I search after class_id but if I give the second condition in filters, which is country_id, unfortunately then nothing returns
推荐答案
这个问题是组合和抽象的一个很好的练习.让我们考虑下划线必须提供的一些功能以及如何使用它们.逐步地,我们会将它们组合成一个更大的整体,直到达到您的目标.
This question is a good exercise in composition and abstraction. Let's consider some of the functions that Underscore has to offer and how we can use them. Gradually, we'll compose these into a larger whole until we've met your goal.
_.contains
接受一个集合(数组或对象)和一个价值.如果集合包含该值,则返回 true
,否则返回 false
.
_.contains([1, 2, 3], 3) // true
_.partial
接受一个函数以及您所使用的任意数量的参数可能需要预填充"作为该函数的参数.然后,它将返回一个新函数,其中预填充了这些参数.您可以将 _
用作要保留为打开状态的参数的占位符.
_.partial
takes a function and any number of arguments that you may want to "pre-fill" as arguments to that function. It then returns a new function with those arguments pre-filled. You can use _
as a placeholder for arguments that you want to leave open.
// a version of _.contains that has the second argument pre-filled
// with the value 3
var contains3 = _.partial(_.contains, _, 3);
// the next line is equivalent to calling _.contains([1, 2, 3], 3)
contains3([1, 2, 3]) // true
_.property
取一个名字并返回一个函数.该函数接受一个对象,并返回带有您传递的名称的属性的值.
_.property
takes a name and returns a function. That function takes an object and returns the value of the property with the name you passed.
var getName = _.property('name');
getName({'name': 'test 1'}) // 'test 1'
_.compose
接受任意数量的函数并返回一个新函数.传递给此新函数的参数将传递给传递给 _.compose
的最右边的函数.然后,从右到左,将调用每个函数,并将函数的结果移至其右边.最后,新函数返回最左边函数的结果.
_.compose
takes any number of functions and returns a new function. The arguments that you pass to this new function are fed to the rightmost function that you passed into _.compose
. Then, from right to left, every function is called with the result of the function to its right. Finally, the new function returns the result of the leftmost function.
// a function that takes an object, reads its class_id property,
// and checks whether that contains the value 3
var classIdContains3 = _.compose(contains3, _.property('class_id'));
classIdContains3({'class_id': [1, 2, 3]}) // true
我们可以将其转换为一个函数,该函数将返回诸如属性包含值检查器"的信息.属性名称和值的任意组合.
We can turn this into a function that will return such a "property contains value checker" for any combination of property name and value.
function propertyContains(name, value) {
return _.compose(
_.partial(_.contains, _, value),
_.property(name)
);
}
var classIdContains3 = propertyContains('class_id', 3);
classIdContains3({'class_id': [1, 2, 3]}) // true
classIdContains3({'class_id': [1, 2]}) // false
var nameContainsE = propertyContains('name', 'e');
nameContainsE({'name': 'test 1'}) // true
nameContainsE({'name': 'Zorro'}) // false
_.filter
包含一个集合和一个条件.它返回一个数组,其中包含集合中符合条件的所有元素.
_.filter
takes a collection and a criterion. It returns an array with all elements of the collection that meet the criterion.
_.filter(data, classIdContains3)
//[
// {'name': 'test 1', 'address': 'New York', 'class_id': [1, 2, 3], 'country': 'USA', 'country_id': 20},
// {'name': 'test 2', 'address': 'Lisbona', 'class_id': [2, 3], 'country': 'Portugal', 'country_id': 12},
// {'name': 'test 5', 'address': 'New York', 'class_id': [3], 'country': 'USA', 'country_id': 20},
//]
除了通过函数作为过滤条件外,类似 _.filter
的函数还允许使用几个声明性的速记.为了根据确切的值检查属性,可以使用以下符号:
Besides passing a function as the filter criterion, functions like _.filter
also allow several declarative shorthands. For checking properties against an exact value, this notation works:
_.filter(data, {'country_id': 20})
//[
// {'name': 'test 1', 'address': 'New York', 'class_id': [1, 2, 3], 'country': 'USA', 'country_id': 20},
// {'name': 'test 3', 'address': 'New York', 'class_id': [2], 'country': 'USA', 'country_id': 20},
// {'name': 'test 4', 'address': 'Atlanta', 'class_id': [2], 'country': 'USA', 'country_id': 20},
// {'name': 'test 5', 'address': 'New York', 'class_id': [3], 'country': 'USA', 'country_id': 20},
//]
要按多个条件缩小结果范围,只需多次过滤即可.
To narrow down the results by multiple criteria, simply filter multiple times.
// first filter pass
var hasClassId3 = _.filter(data, classIdContains3);
// second filter pass (filtering result of the above)
_.filter(hasClassId3, {'country_id': 20})
//[
// {'name': 'test 1', 'address': 'New York', 'class_id': [1, 2, 3], 'country': 'USA', 'country_id': 20},
// {'name': 'test 5', 'address': 'New York', 'class_id': [3], 'country': 'USA', 'country_id': 20},
//]
_.chain
和
_.chain
and _.value
allow for a shorter notation of the above.
_.chain(data)
.filter(classIdContains3)
.filter({'country_id': 20})
.value()
//[
// {'name': 'test 1', 'address': 'New York', 'class_id': [1, 2, 3], 'country': 'USA', 'country_id': 20},
// {'name': 'test 5', 'address': 'New York', 'class_id': [3], 'country': 'USA', 'country_id': 20},
//]
使用 _.each
,我们可以将其转换为一个函数将按任意条件组合进行过滤.
Using _.each
, we can turn this into a function that will filter by arbitrary combinations of criteria.
function multiFilter(data, criteria) {
var result = _.chain(data);
if (criteria.exact) result = result.filter(criteria.exact);
_.each(criteria.contains, function(value, name) {
result = result.filter(propertyContains(name, value));
});
return result.value();
}
multiFilter(data, {
exact: {
country_id: 20,
},
contains: {
class_id: 3,
},
})
//[
// {'name': 'test 1', 'address': 'New York', 'class_id': [1, 2, 3], 'country': 'USA', 'country_id': 20},
// {'name': 'test 5', 'address': 'New York', 'class_id': [3], 'country': 'USA', 'country_id': 20},
//]
multiFilter(data, {
exact: {
country_id: 20,
address: 'New York',
},
contains: {
name: '3',
},
})
//[
// {'name': 'test 3', 'address': 'New York', 'class_id': [2], 'country': 'USA', 'country_id': 20},
//]
multiFilter(data, {
contains: {
address: 'a',
},
})
//[
// {'name': 'test 2', 'address': 'Lisbona', 'class_id': [2, 3], 'country': 'Portugal', 'country_id': 12},
// {'name': 'test 4', 'address': 'Atlanta', 'class_id': [2], 'country': 'USA', 'country_id': 20},
//]
For more Underscore, functional programming, and search, you may also refer to this answer.
这篇关于强调在有多个参数时如何过滤所有对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!