Filter array based on array of filters in Javascript

问题: I have an array of users and also an array of filters. I need to filter users based on the array of filters but when I do it will filter on one array but not the others...

问题:

I have an array of users and also an array of filters.

I need to filter users based on the array of filters but when I do it will filter on one array but not the others

My filters object looks like this:

filters: {
  levels: [],
  locations: ['Laois'],
  subjects: ['Art']
}

My users look like this:

const users = [
  {
    email: 'example1@gmail.com',
    levels: ['Ordinary'],
    location: 'Laois',
    subjects: ['Art', 'German']
  },
  {
    email: 'example2@gmail.com',
    levels: ['Higher', 'Ordinary'],
    location: 'Laois',
    subjects: ['English', 'German']
  }
]

Based on the filter above, once filtered the users should only be one because it contains 'Art' and 'Laois':

[{
    email: 'example1@gmail.com',
    levels: ['Ordinary'],
    location: 'Laois',
    subjects: ['Art', 'German']
  },
]

But I am still getting the two users:

EDIT My Code:

applyFilter = (visable) => {
    let { filters, users } = this.state;
    const { subjects, locations, levels } = filters;


    let filteredUsers = [];
    const filteredData = users.filter((user) =>
      user.subjects.some(subject => subjects.includes(subject)) ||
      locations.some(location => location === user.location) ||
      user.levels.some(level => levels.includes(level))
    );

    console.log(filteredData)


    if (!subjects.length && !locations.length && !levels.length) {
      filteredUsers = users;
    } else {
      filteredUsers = filteredData;
    }

    this.setState({
      filterModalVisible: visable,
      filteredResults: filteredUsers.length >= 0 ? filteredUsers : [],
    });
  }

回答1:

You can do this using filter and every methods by checking if every element from the filters value exist in the user value with the same key.

const filters = {"levels":[],"locations":["Laois"],"subjects":["Art"]}
const users = [{"email":"example1@gmail.com","levels":["Ordinary"],"locations":"Laois","subjects":["Art","German"]},{"email":"example2@gmail.com","levels":["Higher","Ordinary"],"locations":"Laois","subjects":["English","German"]}]

const res = users.filter(user => {
  return Object.entries(filters)
    .every(([key, value]) => {
      if (Array.isArray(value)) {
        return value.every(filter => {
          return user[key] && user[key].includes(filter)
        })
      } else {
        return user[key] == value
      }
    })
})

console.log(res)


回答2:

You can try with filter()

const filters = {
  levels: [],
  locations: ['Laois'],
  subjects: ['Art']
}

const users = [
  {
    email: 'example1@gmail.com',
    levels: ['Ordinary'],
    location: 'Laois',
    subjects: ['Art', 'German']
  },
  {
    email: 'example2@gmail.com',
    levels: ['Higher', 'Ordinary'],
    location: 'Laois',
    subjects: ['English', 'German']
  }
]

var res = users.filter(info => info.location==filters.locations[0] && info.subjects.includes(filters.subjects[0]));

console.log(res);


回答3:

You can have a generic solution for any filter key by using Array.filter, Array.some and Array.includes

  • Use filter to validate each entry against all the filter conditions
  • If an filter condition has an empty list, continue to check for next condition
  • For locations, as the filter key is different from the key in object, add a specific check for that where we check for location to be included in the locations array
  • For other fields, check for existence of atleast 1 entry in array that exists in filter value. If there exists a value, continue to check for next condition.
  • After condition check, confirm if the entry is valid, if not break the loop and return false

let filters = {levels: [],locations: ['Laois'],subjects: ['Art']};
let users = [{email: 'example1@gmail.com',levels: ['Ordinary'],location: 'Laois',subjects: ['Art', 'German']},{email: 'example2@gmail.com',levels: ['Higher', 'Ordinary'],location: 'Laois',subjects: ['English', 'German']}];

users = users.filter(v => {
  let response = true;
  for (let filter in filters) {
    if(!filters[filter].length) continue;
    if(filter === "locations") {
      response = response && filters.locations.includes(v.location)
    } else response = response && v[filter].some(f => filters[filter].includes(f));
    if(!response) break;
  }
  return response;
});
console.log(users);


回答4:

Using filter inside filter

const filters = {
  levels: [],
  locations: ['Laois'],
  subjects: ['Art']
}

const users = [
  {
    email: 'example1@gmail.com',
    levels: ['Ordinary'],
    location: 'Laois',
    subjects: ['Art', 'German']
  },
  {
    email: 'example2@gmail.com',
    levels: ['Higher', 'Ordinary'],
    location: 'Laois',
    subjects: ['English', 'German']
  }
]
console.log(users.filter((e) => {
  var arr = e.subjects.filter((x) => filters.subjects.includes(x))
  if (arr.length > 0 && filters.locations.includes(e.location))
    return e
}))


回答5:

  1. You need to use && instead of || if you want to match all conditions
  2. As per your requirements, you need all of them to match if filter array is empty, so you can just bypass the check for that case

applyFilter = (visable) => {
    let { filters, users } = this.state;
    const { subjects, locations, levels } = filters;

    const filteredResults = users.filter((user) =>
        (!subjects.length || user.subjects.some(subject => subjects.includes(subject))) &&
        (!locations.length || locations.some(location => location === user.location)) &&
        (!levels.length || user.levels.some(level => levels.includes(level)))
    );

    this.setState({
        filterModalVisible: visable,
        filteredResults
    });
}

  • 发表于 2019-02-15 17:03
  • 阅读 ( 203 )
  • 分类:sof

条评论

请先 登录 后评论
不写代码的码农
小编

篇文章

作家榜 »

  1. 小编 文章
返回顶部
部分文章转自于网络,若有侵权请联系我们删除