如何动态过滤对象?

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>