从字符串数组中过滤出对象数组

时间:2019-06-07 01:08:39

标签: javascript

我知道有类似的问题,但是到目前为止,没有一个问题可以帮助我-filtering an array of objects from and array of strings依赖于您知道要匹配的键值对,并且与此问题相同{{3} }

说我有一个像这样的对象数组。

let users = [
    {
       name: 'Steve',
       age: 42,
       pets: {
           dog: 'spike';
       },
       favouriteFood: 'apples'
    },
    {
       name: 'Steve',
       age: 32,
       pets null
       favouriteFood: 'icecream'
    },
    {
       name: 'Jason',
       age: 31,
       pets: null
       favouriteFood: 'tacos'
    },
    {
       name: 'Jason',
       age: 31,
       pets: {
          cat: 'Jerry'
       },
       favouriteFood: 'bread'
    },
]

现在,我希望能够通过匹配任何对象键中的字符串来过滤用户数组。例如,我想过滤掉名字不是'steve'的任何人-请记住,我可能也想过滤掉不是42岁或者最喜欢的食物不是'苹果'的任何人

filter(term) {
    return objects.filter(x => {
        for(let key of Object.keys(x)) {
          if(typeof(x[key]) === 'object') {
              return JSON.stringify(x[key]).toLowerCase().includes(t);
          } else {
             return x[key].toString().toLowerCase().includes(t);
          }
        }
    });
}

现在此功能有效,但仅适用于一个过滤条件

所以如果我运行filter('steve'),我会得到

users = [
    {
       name: 'Steve',
       age: 42,
       pets: {
           dog: 'spike';
       },
       favouriteFood: 'apples'
    },
    {
       name: 'Steve',
       age: 32,
       pets null
       favouriteFood: 'icecream'
    }
]

结果是,但是如果我想过滤掉史蒂夫最喜欢的食物是苹果,那该怎么办?

我尝试如下更新函数,以遍历术语数组并根据数组中的所有字符串进行过滤

所以我尝试过

function filter(terms) {
    return term.forEach((t) => {
      return objects.filter(x => {
        for(let key of Object.keys(x)) {
          if(typeof(x[key]) === 'object') {
              return JSON.stringify(x[key]).toLowerCase().includes(t);
          } else {
             return x[key].toString().toLowerCase().includes(t);
          }
        }
      });
    });

但是当我运行filter(['steve', 'apples'])

我得到undefined

我想要的结果是

users = [
    {
       name: 'Steve',
       age: 42,
       pets: {
           dog: 'spike';
       },
       favouriteFood: 'apples'
    }
]

我不确定自己做错了什么或如何解决此功能,以便使其正常工作。

任何帮助将不胜感激。

2 个答案:

答案 0 :(得分:5)

根据给定用户的.every中是否包含所需数组中的Object.values个值进行过滤:

const filter = arrOfValsNeeded => users.filter(user => {
  const vals = Object.values(user).map(val => typeof val === 'string' ? val.toLowerCase() : val);
  return arrOfValsNeeded.every(needed => vals.includes(needed.toLowerCase()));
});

let users = [
    {
       name: 'Steve',
       age: 42,
       pets: {
           dog: 'spike'
       },
       favouriteFood: 'apples'
    },
    {
       name: 'Steve',
       age: 32,
       pets: null,
       favouriteFood: 'icecream'
    },
    {
       name: 'Jason',
       age: 31,
       pets: null,
       favouriteFood: 'tacos'
    },
    {
       name: 'Jason',
       age: 31,
       pets: {
          cat: 'Jerry'
       },
       favouriteFood: 'bread'
    },
]

console.log(filter(['steve', 'apples']));

或者,如果您需要递归查找所有原始值:

const allPrimitives = obj => {
  const primitives = [];
  JSON.stringify(obj, (key, val) => {
    if (typeof val !== 'object' || val === null) {
      primitives.push(typeof val === 'string' ? val.toLowerCase() : val);
    }
    return val;
  });
  return primitives;
};
const filter = arrOfValsNeeded => users.filter(user => {
  const vals = allPrimitives(user);
  return arrOfValsNeeded.every(needed => vals.includes(needed.toLowerCase()));
});

let users = [
    {
       name: 'Steve',
       age: 42,
       pets: {
           dog: 'spike'
       },
       favouriteFood: 'apples'
    },
    {
       name: 'Steve',
       age: 32,
       pets: null,
       favouriteFood: 'icecream'
    },
    {
       name: 'Jason',
       age: 31,
       pets: null,
       favouriteFood: 'tacos'
    },
    {
       name: 'Jason',
       age: 31,
       pets: {
          cat: 'Jerry'
       },
       favouriteFood: 'bread'
    },
]

console.log(filter(['steve', 'apples']));

如果还需要部分匹配,请使用vals.some代替vals.includes,以便标识子字符串:

const allStrings = obj => {
  const strings = [];
  JSON.stringify(obj, (key, val) => {
    if (typeof val === 'string') {
      strings.push(val.toLowerCase());
    }
    return val;
  });
  return strings;
};
const filter = arrOfValsNeeded => {
  const lowerVals = arrOfValsNeeded.map(str => str.toLowerCase());
  return users.filter(user => {
    const existingStrings = allStrings(user);
    return lowerVals.every(
      lowerNeeded => existingStrings.some(
        existingString => existingString.includes(lowerNeeded)
      )
    );
  });
};

let users = [
    {
       name: 'Steve',
       age: 42,
       pets: {
           dog: 'spike'
       },
       favouriteFood: 'apples'
    },
    {
       name: 'Steve',
       age: 32,
       pets: null,
       favouriteFood: 'icecream'
    },
    {
       name: 'Jason',
       age: 31,
       pets: null,
       favouriteFood: 'tacos'
    },
    {
       name: 'Jason',
       age: 31,
       pets: {
          cat: 'Jerry'
       },
       favouriteFood: 'bread'
    },
]

console.log(filter(['steve', 'apples']));

答案 1 :(得分:1)

对不起,您的回复很晚。我一直试图提出在几乎任何情况下都可以使用的递归代码。最终,我发现了一些非常酷的摘要here,这是我从similar派生equals函数的地方,并出于兼容性考虑。

function similar(a, b){
  if(a === b){
    return true;
  }
  if(a instanceof Date && b instanceof Date){
    return a.getTime() === b.getTime();
  }
  if (!a || !b || (typeof a !== 'object' && typeof b !== 'object')){
    return a === b;
  }
  if (a === null || a === undefined || b === null || b === undefined || a.prototype !== b.prototype){
    return false;
  }
  return Object.keys(b).every(function(k){
    return similar(a[k], b[k]);
  });
}
let users = [
    {
       name: 'Steve',
       age: 42,
       pets: {
           dog: 'spike'
       },
       favouriteFood: 'apples'
    },
    {
       name: 'Steve',
       age: 32,
       pets: null,
       favouriteFood: 'icecream'
    },
    {
       name: 'Jason',
       age: 31,
       pets: null,
       favouriteFood: 'tacos'
    },
    {
       name: 'Jason',
       age: 31,
       pets: {
          cat: 'Jerry'
       },
       favouriteFood: 'bread'
    }
]
var testObj = {name:'Jason', age: 31, pets:{cat:'Jerry'}};
for(var i=0,u,l=users.length; i<l; i++){
  u = users[i];
  if(similar(u, testObj)){
    console.log('contains testObj');
    console.log(u);
  }
  else if(!similar(u, {pets:null}) && !similar(u, {pets:{dog:'spot'}})){
    console.log('not spot');
    console.log(u);
  }
}

similar将查看是否有完全匹配的内容不是对象,或者如果是对象,则将考虑到ab是否包含a b具有相同深度的属性和值,并且b不包含a中不存在的属性。