最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

Filter by multiple keys and values, Javascript - Stack Overflow

programmeradmin8浏览0评论

I'm trying to make a filter. The number of filters will change dynamically, a number of keys can be different, and the number of values, too.

This is how data look like:

var data = [
{id: "123", color: "Red", model: "Tesla"}, 
{id: "124", color: "Black", model: "Honda"}, 
{id: "125", color: "Red", model: "Audi"}, 
{id: "126", color: "Blue", model: "Tesla"}]

Filter keys are color and model. But sometimes I will filter only by color or model and sometimes by both. I want to make a function that will cover both cases. Also, a user can choose many values (Tesla, Honda...).

Key can be only color, or only model, or both. Values can look like: only "Red", "Red" and "Blue", or "Red" and "Tesla", or "Red", "Blue" and "Tesla"... Depends on what user choose.

I tried this:

var filtered = [];
data.forEach(item => {
   filterByKey.forEach(key => {
      values.forEach(value => {
         if (item[key] === value) {
             filtered.push(item);
          }
       });
    });
  });

Here is JsFiddle

My loop works well when I have one filter key, but it doesn't work well when I have more than one key. Is it a good idea to pass keys and values as an array?

No jQuery please, only pure JavaScript.

I'm trying to make a filter. The number of filters will change dynamically, a number of keys can be different, and the number of values, too.

This is how data look like:

var data = [
{id: "123", color: "Red", model: "Tesla"}, 
{id: "124", color: "Black", model: "Honda"}, 
{id: "125", color: "Red", model: "Audi"}, 
{id: "126", color: "Blue", model: "Tesla"}]

Filter keys are color and model. But sometimes I will filter only by color or model and sometimes by both. I want to make a function that will cover both cases. Also, a user can choose many values (Tesla, Honda...).

Key can be only color, or only model, or both. Values can look like: only "Red", "Red" and "Blue", or "Red" and "Tesla", or "Red", "Blue" and "Tesla"... Depends on what user choose.

I tried this:

var filtered = [];
data.forEach(item => {
   filterByKey.forEach(key => {
      values.forEach(value => {
         if (item[key] === value) {
             filtered.push(item);
          }
       });
    });
  });

Here is JsFiddle

My loop works well when I have one filter key, but it doesn't work well when I have more than one key. Is it a good idea to pass keys and values as an array?

No jQuery please, only pure JavaScript.

Share Improve this question asked Jun 16, 2017 at 13:22 snoopy25snoopy25 1,3564 gold badges12 silver badges15 bronze badges
Add a comment  | 

8 Answers 8

Reset to default 12

You can use filter() with every() and check if value of current object with current key exits in values array using includes()

var data = [{"id":"123","color":"Red","model":"Tesla"},{"id":"124","color":"Black","model":"Honda"},{"id":"125","color":"Red","model":"Audi"},{"id":"126","color":"Blue","model":"Tesla"}]

var keys = ["color", 'model'];
var values = ["Tesla", "Audi", "Red"];

var result = data.filter(function(e) {
  return keys.every(function(a) {
    return values.includes(e[a])
  })
})

console.log(result);

You could use a combined approach with a seach object which keeps the conditions, like

{ 
    model: 'Tesla',                                    // a single value
    color: ['red', 'blue'],                            // a some value
    price: {                                           // a range/interval
        min: 2000, 
        max: 3000
    },
    transmission: v => v.toLowerCase() === 'automatic' // a function
}

var useConditions = search => a => Object.keys(search).every(k => 
        a[k] === search[k] ||
        Array.isArray(search[k]) && search[k].includes(a[k]) ||
        typeof search[k] === 'object' && +search[k].min <= a[k] &&  a[k] <= +search[k].max ||
        typeof search[k] === 'function' && search[k](a[k])
    ),
    data = [{ id: "123", color: "Red", model: "Tesla" }, { id: "124", color: "Black", model: "Honda" }, { id: "125", color: "Red", model: "Audi" }, { id: "126", color: "Blue", model: "Tesla" }],
    filters = { color: ['Red', 'Blue'], model: 'Tesla' };

console.log(data.filter(useConditions(filters)));

You can use Array.prototype.filter() where the function to test each element of the array is:

el => !!filterBy.toString().match(new RegExp(`(?=.*${el.color})(?=.*${el.model})`))

It consist of a regular expression new RegExp(`(?=.*${el.color})(?=.*${el.model})`)) that match to strings color and model in another string filterBy.toString()

var data = [{id: "123", color: "Red", model: "Tesla"}, {id: "124", color: "Black", model: "Honda"}, {id: "125", color: "Red", model: "Audi"}, {id: "126", color: "Blue", model: "Tesla"}],
    filterBy = ['Tesla', 'Audi', 'Red', 'Black'],
    result = data.filter(el => !!filterBy.toString().match(new RegExp(`(?=.*${el.color})(?=.*${el.model})`)));

console.log(result);

And also, you can combine Array.prototype.filter() and Array.prototype.includes():

var data = [{id: "123", color: "Red", model: "Tesla"}, {id: "124", color: "Black", model: "Honda"}, {id: "125", color: "Red", model: "Audi"}, {id: "126", color: "Blue", model: "Tesla"}],
    filterBy = ['Tesla', 'Audi', 'Red', 'Black'],
    result = data.filter(el => filterBy.includes(el.model) && filterBy.includes(el.color));

console.log(result);

For a case like this here's what I just do:

function _filter(data, query) { // query = "Red" or "Tesla"
    return data.filter(el => {
        return el.model.toLowerCase().indexOf(query.toLowerCase()) !== -1 ||
        el.name.toLowerCase().indexOf(query.toLowerCase()) !== -1;
    });
}

Now this function searches data on the model key and name key.

Using filter() to filter data, combined with some() to check if multiple keys match at least one of the strings from the values using includes()

// array --------------------

const data = [
  { id: '123', color: 'Red', model: 'Tesla' },
  { id: '124', color: 'Black', model: 'Honda' },
  { id: '125', color: 'Red', model: 'Audi' },
  { id: '126', color: 'Blue', model: 'Tesla' },
];



// filter exact match --------------------

const keysExact = ['color', 'model'];
const valuesExact = ['Tesla', 'Audi', 'Red'];

const resultExact = data.filter((item) =>
  keysExact.every((a) => valuesExact.includes(item[a]))
);

console.log(resultExact);
// result:
// [
//   { id: '123', color: 'Red', model: 'Tesla' },
//   { id: '125', color: 'Red', model: 'Audi' },
// ]; 

Using filter() to filter data, combined with some() to check if multiple keys contain at least one of the strings from the values using includes().

// array --------------------

const data = [
  { id: '123', color: 'Red', model: 'Tesla' },
  { id: '124', color: 'Black', model: 'Honda' },
  { id: '125', color: 'Red', model: 'Audi' },
  { id: '126', color: 'Blue', model: 'Tesla' },
];



// filter data by keys containing values string (at least one of the string in values) --------------------

const keysSome = ['color', 'model'];
const valuesSome = ['Tes', 're'];

const resultSome = data.filter((item) =>
  keysSome.some((key) =>
    valuesSome.some((val) => item[key].toLowerCase().includes(val.toLowerCase()))
  )
);

console.log(resultSome);
// result:
// [
//   { id: '123', color: 'Red', model: 'Tesla' },
//   { id: '125', color: 'Red', model: 'Audi' },
//   { id: '126', color: 'Blue', model: 'Tesla' },
// ];

Using filter() to filter data, combined with every() to check if multiple keys contain all strings from the values using includes().

// array --------------------

const data = [
  { id: '123', color: 'Red', model: 'Tesla' },
  { id: '124', color: 'Black', model: 'Honda' },
  { id: '125', color: 'Red', model: 'Audi' },
  { id: '126', color: 'Blue', model: 'Tesla' },
];



// filter data by keys containing values string (matches all strings from values) --------------------

const keysEvery = ['color', 'model'];
const valuesEvery = ['Tes', 're'];

const resultEvery = data.filter((item) =>
  keysEvery.every((key) =>
    valuesEvery.some((val) => item[key].toLowerCase().includes(val.toLowerCase()))
  )
);

console.log(resultEvery);
// result:
// [
//   { id: '123', color: 'Red', model: 'Tesla' }
// ]

Is this what you want to achieve?

var data = [
  {id: "123", color: "Red", model: "Tesla"}, 
  {id: "124", color: "Black", model: "Honda"}, 
  {id: "125", color: "Red", model: "Audi"}, 
  {id: "126", color: "Blue", model: "Tesla"}
];

var allowedColors = ["Red", "Blue"];
var allowedModels = ["Tesla", "Audi"];

function filter (cars, colors, models) {
  return cars.filter(function (car) {
    return colors.indexOf(car.color) !== -1 && // check if the car's color is allowed
      models.indexOf(car.model) !== -1;        // check if the car's model is allowed
  });
}

var filtered = filter(data, allowedColors, allowedModels);
console.log(filtered);

Filtering is native in JS, try this:

data.filter(item => item.color==='Red');
// or in the old fashion 
data.filter(function(item){ return item.color==='Red';} );

Here, I have a different scenario.

I have an object

d={r1: {name: "r1", validation: true}, r2: {name: "r2", validation: true}};

and another array

a = ["r1"];

Here, the result I want is

d={r1: {name: "r1", validation: true}}
发布评论

评论列表(0)

  1. 暂无评论