3

I know this question has been asked before, but existing solutions do not seem to work for my case. I am trying to filter out data on the basis of multiple properties/values in a varied array of objects.

My sample data looks like this:

const products = [
          { name: 'A', color: 'Blue', size: 50, locations: 'USA' },
          { name: 'B', color: 'Blue', size: 60, locations: 'Europe' },
          { name: 'C', color: 'Blue', size: 30, locations: 'Europe' },
          { name: 'D', color: 'Black', size: 70, locations: 'Japan' },
          { name: 'E', color: 'Green', size: 50, locations: 'Europe' },
          { name: 'F', color: 'Blue', size: 50, locations: 'Brazil' },
          { name: 'G', color: 'Black', size: 40, locations: 'Australia' },
        ];

This is what I require the filters result to be:

const filters_one = ['Blue'];

const requiredResult_One = [
      { name: 'A', color: 'Blue', size: 50, locations: 'USA' }, 
      { name: 'B', color: 'Blue', size: 60, locations: 'Europe' },
      { name: 'C', color: 'Blue', size: 30, locations: 'Europe' },
      { name: 'E', color: 'Blue', size: 50, locations: 'Brazil' }, 
]


const filters_two = ['Blue', 'Europe'];

const requiredResult_Two = [
      { name: 'B', color: 'Blue', size: 60, locations: 'Europe' },
      { name: 'C', color: 'Blue', size: 30, locations: 'Europe' }, 
]


----------OR-------------------------
const filters_three = ['Black'];

const requiredResult_three = [
      { name: 'D', color: 'Black', size: 70, locations: 'Japan' },
      { name: 'G', color: 'Black', size: 40, locations: 'Australia' }, 
]

const filters_four = ['Black', 'Japan'];

const requiredResult_Four = [
      { name: 'D', color: 'Black', size: 70, locations: 'Japan' },
]

this is what I have achieved so far:

const filterdata = (products, filter) => {
      // where, filter can be equal to *filters_one*, *filters_two*, *filters_three*, 
         or *filters_four* anyone of it. //

      const keysExact = ['color', 'locations'];
      const valuesExact = filter.map(col => col.toLowerCase());

      const resultExact = products.filter((prod) =>
          keysExact.every((key) => valuesExact.includes(prod[key].toLowerCase()))
      );

      console.log(resultExact);
};

This seems to work partially or not looks like a good approach to me. If anyone can help me with a way better solution on this, will be really helpful.

Thanks in advance!

4 Answers 4

5

You could get the values from the object and check if all values of the query is in the values array.

const
    filter = (data, query) => data.filter(o => {
        const values = Object.values(o);
        return query.every(q => values.includes(q));
    }),
    products = [{ name: 'A', color: 'Blue', size: 50, locations: 'USA' }, { name: 'B', color: 'Blue', size: 60, locations: 'Europe' }, { name: 'C', color: 'Blue', size: 30, locations: 'Europe' }, { name: 'D', color: 'Black', size: 70, locations: 'Japan' }, { name: 'E', color: 'Green', size: 50, locations: 'Europe' }, { name: 'F', color: 'Blue', size: 50, locations: 'Brazil' }, { name: 'G', color: 'Black', size: 40, locations: 'Australia' }];

console.log(filter(products, ['Blue']));
console.log(filter(products, ['Blue', 'Europe']));
console.log(filter(products, ['Black']));
console.log(filter(products, ['Black', 'Japan']));
console.log(filter(products, [['Blue', 'Green']]));
.as-console-wrapper { max-height: 100% !important; top: 0; }

An approach for alternate values of the same key.

const
    filter = (data, query) => data.filter(o => {
        const values = Object.values(o);
        return query.every(q =>
            values.includes(q) ||
            Array.isArray(q) && q.some(v => values.includes(v))
        );
    }),
    products = [{ name: 'A', color: 'Blue', size: 50, locations: 'USA' }, { name: 'B', color: 'Blue', size: 60, locations: 'Europe' }, { name: 'C', color: 'Blue', size: 30, locations: 'Europe' }, { name: 'D', color: 'Black', size: 70, locations: 'Japan' }, { name: 'E', color: 'Green', size: 50, locations: 'Europe' }, { name: 'F', color: 'Blue', size: 50, locations: 'Brazil' }, { name: 'G', color: 'Black', size: 40, locations: 'Australia' }];

console.log(filter(products, ['Blue']));
console.log(filter(products, [['Blue', 'Green']]));
.as-console-wrapper { max-height: 100% !important; top: 0; }

Sign up to request clarification or add additional context in comments.

7 Comments

Nice and clean! But can you explain please the comma at the end of line 5.
do you mean after })? if so, it separates the const declarations and initializations.
@NinaScholz Thanks for the clean solution. Can you please help with something more? If I filter only on the basis of two or more colors only, like ['Blue', 'Green'], it should return data that belongs from these two colors but it does not give any result. Can you please help tweak this solution a bit?
actually all values are required for the filtering. if you want an alternate value for the same key, you could use an array for it and check with Array#some.
@NinaScholz So with this new approach, data can be filtered on the basis of any values combination? I mean, any combination of color and location OR color or location?
|
1

You can create a filter based on color and location

const products = [
  { name: 'A', color: 'Blue', size: 50, locations: 'USA' },
  { name: 'B', color: 'Blue', size: 60, locations: 'Europe' },
  { name: 'C', color: 'Blue', size: 30, locations: 'Europe' },
  { name: 'D', color: 'Black', size: 70, locations: 'Japan' },
  { name: 'E', color: 'Green', size: 50, locations: 'Europe' },
  { name: 'F', color: 'Blue', size: 50, locations: 'Brazil' },
  { name: 'G', color: 'Black', size: 40, locations: 'Australia' },
];

function filterProducts(filterParams) {
  const [color, country] = filterParams;
  const output = products.filter((product) => product.color === color && (country ? product.locations  === country : true))
  return output;
}
const filters_one = ['Blue'];
const requiredResult_One = filterProducts(filters_one);
console.log(requiredResult_One);


const filters_two = ['Blue', 'Europe'];
const requiredResult_Two = filterProducts(filters_two);
console.log(requiredResult_Two);


const filters_three = ['Black'];
const requiredResult_three = filterProducts(filters_three);
console.log(requiredResult_three);

const filters_four = ['Black', 'Japan'];
const requiredResult_Four = filterProducts(filters_four);
console.log(requiredResult_Four);

Comments

1
const filterArray = (filter, arr) => {
   return arr.filter(val => (filter[1] 
                       ? val.color === filter[0] && val.locations === filter[1] 
                       : val.color === filter[0]));
};

Comments

1

You can use an object to filter list:

let products = [{ name: 'A', color: 'Blue', size: 50, locations: 'USA' }, { name: 'B', color: 'Blue', size: 60, locations: 'Europe' }, { name: 'C', color: 'Blue', size: 30, locations: 'Europe' }, { name: 'D', color: 'Black', size: 70, locations: 'Japan' }, { name: 'E', color: 'Green', size: 50, locations: 'Europe' }, { name: 'F', color: 'Blue', size: 50, locations: 'Brazil' }, { name: 'G', color: 'Black', size: 40, locations: 'Australia' },];
function* filter(array, list = {}) {
    loop: for (let item of array) {
        for (let [k, v] of Object.entries(list))
            if (item[k] != v)
                continue loop;

        yield item;
    }
}
console.log("size:50", [...filter(products, { size: 50 })])
console.log("color:Blue", [...filter(products, { color: 'Blue' })])
console.log("color:Blue, size:50", [...filter(products, { color: 'Blue', size: 50 })])
console.log("color:Blue, locations:Europe", [...filter(products, { color: 'Blue', locations: 'Europe' })])

This example is very fast, flexible and lazy!

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.