如何动态过滤对象?
How to Filter objects dynamically?
我有一个 Javascript 数组:
var peoples = [
{'people':{'sex':'male', 'diet':'vegetarian','favPlaces':['place1','place2']}},
{'people':{'sex':'female', 'diet':'flexitarian','favPlaces':['place2','place3']}},
{'people':{'sex':'male', 'diet':'flexitarian', 'favPlaces':['place4','place1']}}
];
如果我select {'sex':['female','male']} && {'diet' :['flexitarian']} 输出应该是 ['place2', 'place3', 'place4', 'place1']。
我的代码的问题是如果我只 select 'sex' 它不会显示结果但是如果我 select 两个 'sex' 和 'diet' 它会显示结果。
我不知道如何让我的代码动态化,这样当我 select 做爱或节食或做爱和节食时,代码会动态过滤,它们会显示结果。
这是我的代码:
var filterObj = {'sex': ['female', 'male'], 'diet': ['flexitarian']};
for(var p in peoples){
for(var s in filterObj.sex){
for(var d in filterObj.diet){
if((filterObj.sex[s] == peoples[p].people.sex) && (filterObj.diet[d] == peoples[p].people.diet)){
console.log(peoples[p].people.favPlaces);
}
}
}
这是HTML:
<ul id="sex">
<li><label><input type="checkbox" value="male">Male</label></li>
<li><label><input type="checkbox" value="female">Female</label></li>
</ul>
<ul id="diet">
<li><label><input type="checkbox" value="none">None</label></li>
<li><label><input type="checkbox" value="flexitarian">Flexitarian</label></li>
<li><label><input type="checkbox" value="vegetarian">Vegetarian</label></li>
</ul>
您可以使用 Array.indexOf
并反转条件,例如...检查是否可以在条件内找到单个数据,但如果其中没有任何内容(通过检查其长度),也可以忽略过滤器作为如下所示...
var matchingSet = peoples.filter(function(p) {
return (filterObj.sex.length === 0 || filterObj.sex.indexOf(p.people.sex) !== -1) //peoples' sex must exists in the filter.sex or ignore it if filter not specified
&& (filterObj.diet.length === 0 || filterObj.diet.indexOf(p.people.diet) !== -1); //and people's diet must exists in the filter.diet or ignore it if filter not specified
});
之后,使用 Array.map
从匹配集中拉出 favPlaces。
var matchingPlaces = matchingSet.map(function(p) { return p.people.favPlaces; });
最后,使用 Underscore(比自己制作更容易,因为我认为还没有原生的 JavaScript Array 方法...来展平,从 favPlaces 数组中提取唯一值并对其进行排序(作为额外奖励):
var flatten = _.chain(matchingPlaces)
.flatten()
.uniq()
.sortBy(function(p) { return p; })
.value();
这将为您提供所需的结果。
["place1","place2","place3","place4"]
完整示例可在以下位置找到:http://jsfiddle.net/rdfyp5c9/2/
请注意,在示例中我删除了饮食过滤器元素:
var filterObj = {
'sex' : ['male'],
'diet': []
};
它正在正确返回
["place1","place2","place4"]
结果。
您绝对可以在 matchingSet 赋值行细化过滤器以检查 filterObj.sex 是否为真,如果它是数组等则只执行长度检查,但为了简单起见...这个特定的解决方案假设如果你不想在过滤器中节食,则需要将空数组作为节食传递...
使用开源项目jinqJs应该很容易
var peoples = [
{'people':{'sex':'male', 'diet':'vegetarian','favPlaces':['place1','place2']}},
{'people':{'sex':'female', 'diet':'flexitarian','favPlaces':['place2','place3']}},
{'people':{'sex':'male', 'diet':'flexitarian', 'favPlaces':['place4','place1']}}
];
var result = jinqJs().from(peoples).where(function(row){return (row.people.sex === 'female' || row.people.diet === 'flexitarian');}).select(function(row){return row.people.favPlaces;});
document.body.innerHTML = '<pre>' + JSON.stringify(result, null, 4) + '</pre><br><br>';
<script src="https://rawgit.com/fordth/jinqJs/master/jinqjs.js"></script>
我有一个 Javascript 数组:
var peoples = [
{'people':{'sex':'male', 'diet':'vegetarian','favPlaces':['place1','place2']}},
{'people':{'sex':'female', 'diet':'flexitarian','favPlaces':['place2','place3']}},
{'people':{'sex':'male', 'diet':'flexitarian', 'favPlaces':['place4','place1']}}
];
如果我select {'sex':['female','male']} && {'diet' :['flexitarian']} 输出应该是 ['place2', 'place3', 'place4', 'place1']。
我的代码的问题是如果我只 select 'sex' 它不会显示结果但是如果我 select 两个 'sex' 和 'diet' 它会显示结果。 我不知道如何让我的代码动态化,这样当我 select 做爱或节食或做爱和节食时,代码会动态过滤,它们会显示结果。
这是我的代码:
var filterObj = {'sex': ['female', 'male'], 'diet': ['flexitarian']};
for(var p in peoples){
for(var s in filterObj.sex){
for(var d in filterObj.diet){
if((filterObj.sex[s] == peoples[p].people.sex) && (filterObj.diet[d] == peoples[p].people.diet)){
console.log(peoples[p].people.favPlaces);
}
}
}
这是HTML:
<ul id="sex">
<li><label><input type="checkbox" value="male">Male</label></li>
<li><label><input type="checkbox" value="female">Female</label></li>
</ul>
<ul id="diet">
<li><label><input type="checkbox" value="none">None</label></li>
<li><label><input type="checkbox" value="flexitarian">Flexitarian</label></li>
<li><label><input type="checkbox" value="vegetarian">Vegetarian</label></li>
</ul>
您可以使用 Array.indexOf
并反转条件,例如...检查是否可以在条件内找到单个数据,但如果其中没有任何内容(通过检查其长度),也可以忽略过滤器作为如下所示...
var matchingSet = peoples.filter(function(p) {
return (filterObj.sex.length === 0 || filterObj.sex.indexOf(p.people.sex) !== -1) //peoples' sex must exists in the filter.sex or ignore it if filter not specified
&& (filterObj.diet.length === 0 || filterObj.diet.indexOf(p.people.diet) !== -1); //and people's diet must exists in the filter.diet or ignore it if filter not specified
});
之后,使用 Array.map
从匹配集中拉出 favPlaces。
var matchingPlaces = matchingSet.map(function(p) { return p.people.favPlaces; });
最后,使用 Underscore(比自己制作更容易,因为我认为还没有原生的 JavaScript Array 方法...来展平,从 favPlaces 数组中提取唯一值并对其进行排序(作为额外奖励):
var flatten = _.chain(matchingPlaces)
.flatten()
.uniq()
.sortBy(function(p) { return p; })
.value();
这将为您提供所需的结果。
["place1","place2","place3","place4"]
完整示例可在以下位置找到:http://jsfiddle.net/rdfyp5c9/2/
请注意,在示例中我删除了饮食过滤器元素:
var filterObj = {
'sex' : ['male'],
'diet': []
};
它正在正确返回
["place1","place2","place4"]
结果。
您绝对可以在 matchingSet 赋值行细化过滤器以检查 filterObj.sex 是否为真,如果它是数组等则只执行长度检查,但为了简单起见...这个特定的解决方案假设如果你不想在过滤器中节食,则需要将空数组作为节食传递...
使用开源项目jinqJs应该很容易
var peoples = [
{'people':{'sex':'male', 'diet':'vegetarian','favPlaces':['place1','place2']}},
{'people':{'sex':'female', 'diet':'flexitarian','favPlaces':['place2','place3']}},
{'people':{'sex':'male', 'diet':'flexitarian', 'favPlaces':['place4','place1']}}
];
var result = jinqJs().from(peoples).where(function(row){return (row.people.sex === 'female' || row.people.diet === 'flexitarian');}).select(function(row){return row.people.favPlaces;});
document.body.innerHTML = '<pre>' + JSON.stringify(result, null, 4) + '</pre><br><br>';
<script src="https://rawgit.com/fordth/jinqJs/master/jinqjs.js"></script>