In plain Javascript, trying to filter for multiple values in an array that contains User objects that contain other objects and arrays

谁说我不能喝 提交于 2021-02-05 07:27:26

问题


thanks for taking a look at this. Sorry for length, trying to be clear!

WHAT I'M TRYING TO DO: I have an array of users (each user an object) and am trying to filter the users on multiple criteria ("males from France" OR "females from Spain and United States with Engineering skills" etc) but it's proven beyond my skills so far.

The hard part has been that the users are objects within a User array, but within each user object, some values are additional objects or arrays. Here's what the user data array looks like (abbreviated):

let users = [
{ 
gender: 'male', 
location: {street: 'Clement Street', country: 'United States'},
skills: ['engineering', 'underwater'], 
}, ...

Notice gender is just a normal property/value but country is within a location object and skills are within an array.

I already have a search button interface that creates toggle buttons to search on each criteria available, and every time you click a button, I add or remove that criteria in a filter object. The filter object looks like this, and uses arrays inside it so that I can define multiple criteria at once, like multiple countries to search, multiple skills, etc.:

    filter: {
        gender: ['female'],
    location: {
    country: ['Spain'],},
    skills: ['optics', ]
    },

WHERE I REALLY GET STUCK I've created a filterData method that can successfully filter based on Gender (male or female) but can't get it to ALSO filter on country (within the location object) or skills (within the skills array). My current filterData method only goes through one iteration per user, but I've tried For loops and forEach to try to go through each of the filter's criteria ('Spain', 'Optics'), but it just doesn't work. I only get gender.

I think I have two problems: 1) somehow conveying in the code that the item 'key' in some cases will not be a value, but an object or array that must also be searched within, and 2) creating some kind of looping behavior that will go through each of the filter criteria, instead of stopping after the first one (gender).

That's apparently over my head right now, so any guidance or suggestions would be appreciated, thanks very much! And here's all the code I've been working with, including my filterData method.

var filtering = {
  filter: {
    gender: ["female"],
    location: {
      country: ["Spain"],
    },
    skills: ["optics"],
  },

  users: [
    {
      gender: "male",
      name: "John",
      location: { street: "Clement Street", country: "United States" },
      skills: ["engineering", "underwater"],
    },

    {
      gender: "female",
      name: "Mary",
      location: { street: "5th Avenue", country: "Spain" },
      skills: ["confidence", "optics"],
    },

    {
      gender: "male",
      name: "David",
      location: { street: "Vermont Ave", country: "France" },
      skills: ["cards", "metalurgy", "confidence"],
    },

    {
      gender: "female",
      name: "Rachel",
      location: { street: "Vermont Ave", country: "France" },
      skills: ["disguise", "electrical"],
    },

    {
      gender: "female",
      name: "Muriel",
      location: { street: "Vermont Ave", country: "Germany" },
      skills: ["flight", "surveillance"],
    },
  ],

  filterData: (filter) => {
    const filteredData = filtering.users.filter((item) => {
      for (let key in filter) {
        if (!filter[key].includes(item[key])) {
          return false;
        }
        return true;
      }
    });
    console.log(filteredData);
  },
};

filtering.filterData(filtering.filter);

回答1:


There's a nifty trick called recursion, which is a function calling itself.

The updated code are: checkUserand filterData

var filtering = {
  filter: {
    gender: ["female"],
    location: {
      country: ["Spain"],
    },
    skills: ["optics"],
  },

  users: [
    {
      gender: "male",
      name: "John",
      location: { street: "Clement Street", country: "United States" },
      skills: ["engineering", "underwater"],
    },

    {
      gender: "female",
      name: "Mary",
      location: { street: "5th Avenue", country: "Spain" },
      skills: ["confidence", "optics"],
    },

    {
      gender: "male",
      name: "David",
      location: { street: "Vermont Ave", country: "France" },
      skills: ["cards", "metalurgy", "confidence"],
    },

    {
      gender: "female",
      name: "Rachel",
      location: { street: "Vermont Ave", country: "France" },
      skills: ["disguise", "electrical"],
    },

    {
      gender: "female",
      name: "Muriel",
      location: { street: "Vermont Ave", country: "Germany" },
      skills: ["flight", "surveillance"],
    },
  ],
  
  checkUser (filter, to_check) {
    if (Array.isArray(filter))
    {
      return Array.isArray(to_check)
        ? filter.some(val => to_check.includes(val)) // if what we're checking is an array
        : filter.includes(to_check); // otherwise it's a singular value
    }
    else
    {
      const all_checks = []; // this is to save every return value from the recursive function
      for (let key in filter) // going through each key in the filter
      {
        const checked = this.checkUser(filter[key], to_check[key]) // passing two values, which will be compared with each other
        all_checks.push(checked) // pushing the checked result
      }
      
      return all_checks.every(val => val) // checking that it passes the filter by ensuring every value is true
    }
  },

  filterData () {
    let filter = this.filter
    return this.users.filter(user => this.checkUser(filter, user))
  },
};

// filtering.filterData(filtering.filter);

// filtering.checkUser(filtering.filter, filtering.users[0])
const result = filtering.filterData()
console.log(result)



回答2:


Bit complex data structure, you should clean. However, solved what expected.

const mergeFilter = (item, [key, value]) => {
  let val = Array.isArray(item[key]) ? item[key] : [item[key]];
  let m = value[0];
  if (typeof value === "object" && !Array.isArray(value)) {
    const k2 = Object.keys(value);
    val = item[key][k2];
    m = value[k2][0];
  }
  return val.includes(m);
};
const filterData = (users, filter) => {
  const filters = Object.entries(filter);
  const result = users.reduce((arr, item) => {
    let found = filters.every(mergeFilter.bind(null, item));
    if (found) arr.push(item);
    return arr;
  }, []);
  return result;
};

var filtering = {"filter":{"gender":["female"],"location":{"country":["Spain"]},"skills":["optics"]},"users":[{"gender":"male","name":"John","location":{"street":"Clement Street","country":"United States"},"skills":["engineering","underwater"]},{"gender":"female","name":"Mary","location":{"street":"5th Avenue","country":"Spain"},"skills":["confidence","optics"]},{"gender":"male","name":"David","location":{"street":"Vermont Ave","country":"France"},"skills":["cards","metalurgy","confidence"]},{"gender":"female","name":"Rachel","location":{"street":"Vermont Ave","country":"France"},"skills":["disguise","electrical"]},{"gender":"female","name":"Muriel","location":{"street":"Vermont Ave","country":"Germany"},"skills":["flight","surveillance"]}]}

const result = filterData(filtering.users, filtering.filter);
console.log(result)


来源:https://stackoverflow.com/questions/61538865/in-plain-javascript-trying-to-filter-for-multiple-values-in-an-array-that-conta

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!