2017-07-23 61 views
1

我想过滤具有对象数组内的对象数组。例如,数组中的对象看起来像这样。更简单的过滤对象数组对象数组的方法

list=[..., 
    { 
     "types": [ 
      { 
      "slot": 2, 
      "type": 
       { 
        "url": "http://pokeapi.co/api/v2/type/4/", 
        "name": "poison" 
       } 
      }, 
      { 
      "slot": 1, 
      "type": 
       { 
        "url": "http://pokeapi.co/api/v2/type/12/", 
        "name": "grass" 
       } 
      } 
     ], 
     "name": 'bulbasaur' 
    },... 
] 

我目前正在过滤其名称的列表和类型,如该对象(在this.props.search.search是一个字符串,例如是字符串的例子清单将被调整):

let filtered = this.props.pokemons.filter((pokemon)=>{ 
     return pokemon.name.toLowerCase().indexOf(this.props.search.search.toLocaleLowerCase())!==-1; 
    }) 
    let example = ['fire', 'ice', 'water']; 
    let filteredx= filtered.filter((pokemon)=>{ 
     return pokemon.types.filter((type)=>{ 
      return example.indexOf(type.type.name)!==-1 
     }).length>0 
    }) 

是否有所有过滤器组合成一个而不是调用

array.filter(...).filter(...) 

作为未来的一个方法,如果添加了更多的过滤器,我担心它会结束向上看起来像

array.filter(...).filter(...).filter(...).filter(...).filter(...) 

任何帮助,将不胜感激。

+0

考虑使用'const',而不是'let'尽可能。它使您的代码更具可预测性。 – ideaboxer

回答

1

您可以用&&两个条件结合起来:

let filteredx = this.props.pokemons.filter(pokemon => 
    pokemon.name.toLowerCase().includes(this.props.search.search.toLocaleLowerCase()) 
    && pokemon.types.some(type => example.includes(type.type.name)) 
) 

注意,你可以在你的条件下使用includessome,并使用您的箭头功能的表达式语法(不含括号也不return)。

您可以使用其他&&操作员添加更多条件。确保按照最简单的条件(需要最少工作)的顺序放置它们。

+0

谢谢大家的回答,但是这个看起来像是我正在寻找的那个! – Iruss

0

如果数组很小并且性能不是问题;

const arryOfPokemons = [{name: 'name1', type: 'type1'}]; 

function name(pokemon) { return pokemon.name !== 'name' } 

function type(pokemon) { return pokemon.type !== 'type' } 

const result = [name, type].reduce((result, filterFunc) => result.filter(filterFunc), arryOfPokemons); 

否则,您可以尝试将条件组合成相同的过滤器函数。

0

不是多次过滤,您可以将一个过滤器中的所有过滤条件组合在一起。

而不是做这个的......

let filtered1 = toFilter.filter((element) => { 
    return condition1; 
}); 

let filtered2 = filtered1.filter((element) => { 
    return condition2; 
}); 

... 

let filteredN = filteredN_1.filter((element) => { 
    return conditionN; 
}); 

...你可以在一个单一的过滤器相结合的条件:

let filtered = toFilter.filter((element) => { 
    return condition1 && condition2 && ... && conditionN; 
}); 

如果其中一个条件是很长的,你可以很容易地在一个单独的函数中抽象它。这也使代码更具可读性和可维护性。

let filtered = toFilter.filter((element) => { 
    const condition1 = computeCondition1(arg1, arg2); 
    const condition2 = computeCondition2(arg1); 
    ... 
    const condition3 = computeCondition3(arg2, arg3, arg4); 

    return condition1 && condition2 && ... && conditionN; 
}); 
+0

为什么'const'而不是'let'? – ideaboxer

+0

@ideaboxer,很好的观察。编辑... – ninjin

0

您可以定义一个对象,其中包含您要测试的宠物小精灵列表的每个第一级属性的属性。该值将成为此属性的“测试逻辑”的谓词。

const pokemons = [ 
 
    {"name":"poke1","types":[{"type":{"name":"poison"}},{"type":{"name":"grass"}}]}, 
 
    {"name":"poke2","types":[{"type":{"name":"fire"}},{"type":{"name":"grass"}}]}, 
 
    {"name":"poke3","types":[{"type":{"name":"ice"}},{"type":{"name":"water"}}]}, 
 
    {"name":"poke4","types":[{"type":{"name":"ice"}},{"type":{"name":"grass"}}]} 
 
]; 
 

 
const filterOptions = { 
 
    name: (name) => { 
 
    return ["poke1", "poke5"].some(x => x === name); 
 
    }, 
 
    types: (types) => { 
 
    return ["ice", "water"].some(t => types.some(x => t === x.type.name)); 
 
    } 
 
}; 
 

 
function filterList(list, options) { 
 
    return list.filter(pokemon => { 
 
    return Object.keys(filterOptions) 
 
       .some(key => { 
 
        if (key in pokemon) { 
 
        return filterOptions[key](pokemon[key]); 
 
        } 
 
       }); 
 
    }); 
 
} 
 

 
const filtered = filterList(pokemons, filterOptions); 
 
filtered.forEach(p => console.log(JSON.stringify(p)));