peter flanagan
peter flanagan

Reputation: 9830

filter objects based on values and arrays as values js

I am trying to create a filter that is working when the object is a single value, but when introducing an array of keywords I am having issues.

My code looks like the following:

const filter = {
  colors: ["white"],
  sizes: [9, 12],
  brands: ["adidas"],
  keywords: ["running", "weights"]
};

const shoes = [{
    brand: "adidas",
    size: 9,
    color: "white",
    keywords: ["running"]
  },
  {
    brand: "adidas",
    size: 12,
    color: "white",
    keywords: ["weigths"]
  },
  {
    brand: "nike",
    size: 7,
    color: "red",
    keywords: ["running", "tennis"]
  }
];


const properties = {
  colors: 'color',
  sizes: 'size',
  brands: 'brand',
  keywords: 'keywords',
}

const filters = Object
  .entries(filter)
  .filter(([, {
    length
  }]) => length)
  .map(([k, v]) => [properties[k], v]);

const result = shoes.filter(shoe => filters.every(([k, v]) => v.includes(shoe[k])));

console.log('result', result)

The result that I am looking for is

const results = {
    brand: "nike",
    size: 9,
    color: "white",
    keywords: ["running"]
  },
  {
    brand: "adidas",
    size: 12,
    color: "white",
    keywords: ["swimming"]
  }]

Upvotes: 0

Views: 95

Answers (3)

Nina Scholz
Nina Scholz

Reputation: 386868

By having matching words withou spellin g differences, you could create an array of every value and check against the wanted values.

const
    filter = { colors: ["white"], sizes: [9, 12], brands: ["adidas"], keywords: ["running", "weights"] },
    shoes = [{ brand: "nike", size: 9, color: "white", keywords: ["running"] }, { brand: "adidas", size: 12, color: "white", keywords: ["weights"] }, { brand: "nike", size: 7, color: "red", keywords: ["running", "tennis"] }],
    properties = { colors: 'color', sizes: 'size', brands: 'brand', keywords: 'keywords' },
    filters = Object
        .entries(filter)
        .filter(([, { length }]) => length)
        .map(([k, v]) => [properties[k], v]),
    result = shoes.filter(
        shoe => filters.every(
            ([k, v]) => [].concat(shoe[k]).some(value => v.includes(value))
        )
    );

console.log('result', result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Upvotes: 1

isaacsan 123
isaacsan 123

Reputation: 1168

The following should take filter out any object that has a value inconsistent with the filters:

const filterObjectArray = (filters, array) => {
  return array.filter(obj => {
  
    // iterate through each key in filters
    for (let i in filters) {
    
      const objVal = obj[properties[i]]
    
      // here, we can use flatMap to "spread" objVal and filters[i] into
      // an array, whether or not objVal is an array
      const combinedValues = [objVal, filters[i]].flatMap(x => x)
      
      // convert the combinedValues into a Set to remove duplicates
      const set = new Set(combinedValues)
      
      // If the size of the set matches the length of combinedValues
      // it means that objVal and filters[i] have no values in common, so we
      // can just return false.
      if (set.size === combinedValues.length) return false
    }
    
    // If we reach here, it means every value in object has been validated by every key/value in filters.
    return true
  })
}

Here's a repl where you can see this code in action: https://replit.com/@isaacsan123/filtering-objects

Upvotes: 0

Rajdeep D
Rajdeep D

Reputation: 3920

My assumption, you are filtering by size, color and keywords not by brand and based on that I produced the code below, but if the assumption is not valid please provide more details

You can use array.filter to filter an array by passing conditions

let result = shoes.filter(f => filter.sizes.includes(f.size) 
                  && filter.colors.includes(f.color) 
                  && filter.keywords.some(k => f.keywords.includes(k))
             )

console.log(result);

Upvotes: 0

Related Questions