skip to Main Content

I have an array of objects.

vehicles = [
  { "name": "Ford", "type": "SUV", "brand": "Explorer" },
  { "name": "Ford", "type": "SUV", "brand": "Explorer" },
  { "name": "Ford", "type": "truck", "brand": "F-150" },
  { "name": "Chrysler", "type": "car", "brand": "Sierra" },
  { "name": "GM", "type": "truck", "brand": "Sierra" },
  { "name": "GM", "type": "truck", "brand": "Sierra" },
]

How do I filter this by two properties of the objects so there is only one of each? Say name and brand have to be the same?

vehicles = [
  { "name": "Ford", "type": "SUV", "brand": "Explorer" },
  { "name": "Ford", "type": "truck", "brand": "F-150" },
  { "name": "Chrysler", "type": "car", "brand": "Sierra" },
  { "name": "GM", "type": "truck", "brand": "Sierra" },
]

This isn’t working:

const filteredVehicles = vehicles.filter((item) => item.name === name & item.brand === brand );

3

Answers


  1. There are libraries that could help with this, but to do it with vanilla JavaScript, filter should be fine. In the example below filter is used to return elements where there are no elements later in the array that don’t match.

    const vehicles = [
      { "name": "Ford", "type": "SUV", "brand": "Explorer" },
      { "name": "Ford", "type": "SUV", "brand": "Explorer" },
      { "name": "Ford", "type": "truck", "brand": "F-150" },
      { "name": "Chrysler", "type": "car", "brand": "Sierra" },
      { "name": "GM", "type": "truck", "brand": "Sierra" },
      { "name": "GM", "type": "truck", "brand": "Sierra" },
    ];
    
    const reduced = vehicles.filter((el, i, ary) => !ary.slice(i + 1)
      .some(x => x.name === el.name && x.brand === el.brand));
    console.log(reduced);

    Feel free to change the expression inside of some to match by just the brand.

    Login or Signup to reply.
  2. Here’s a generic function that you can supply an array of props to. It keeps track of the same props by using a Set corresponding to each property, meaning it runs in O(nm) time, where n is the length of the array and m is the number of properties checked.

    function filterByProps(arr, props) {
        const sets = props.map((prop) => [prop, new Set()])
    
        return arr.filter((item) => {
            let numSameProps = 0
    
            for (const [prop, set] of sets) {
                if (set.has(item[prop])) {
                    ++numSameProps
                } else {
                    set.add(item[prop])
                }
            }
    
            return numSameProps < props.length
        })
    }
    
    const vehicles = [
        { "name": "Ford", "type": "SUV", "brand": "Explorer" },
        { "name": "Ford", "type": "SUV", "brand": "Explorer" },
        { "name": "Ford", "type": "truck", "brand": "F-150" },
        { "name": "Chrysler", "type": "car", "brand": "Sierra" },
        { "name": "GM", "type": "truck", "brand": "Sierra" },
        { "name": "GM", "type": "truck", "brand": "Sierra" },
    ]
    
    for (const propList of [['brand'], ['name', 'brand'], ['name', 'brand', 'type']]) {
        const results = filterByProps(vehicles, propList)
        console.log(new Intl.ListFormat('en-US').format(propList))
        console.log('length', results.length)
        console.log(results)
    }
    Login or Signup to reply.
  3. Using reduce and Object.values to generate a unique key can filter on all the properties.

    const vehicles = [
      { "name": "Ford", "type": "SUV", "brand": "Explorer" },
      { "name": "Ford", "type": "SUV", "brand": "Explorer" },
      { "name": "Ford", "type": "truck", "brand": "F-150" },
      { "name": "Chrysler", "type": "car", "brand": "Sierra" },
      { "name": "GM", "type": "truck", "brand": "Sierra" },
      { "name": "GM", "type": "truck", "brand": "Sierra" },
    ];
    
    const deduped = Object.values(vehicles.reduce((o, v) => {
      o[Object.values(v).join("-")] = v;
      return o;
    }, {}));
    
    console.log(deduped);

    If you only want to filter on specific ones

    const vehicles = [
      { "name": "Ford", "type": "SUV", "brand": "Explorer" },
      { "name": "Ford", "type": "SUV", "brand": "Explorer" },
      { "name": "Ford", "type": "truck", "brand": "F-150" },
      { "name": "Chrysler", "type": "car", "brand": "Sierra" },
      { "name": "GM", "type": "truck", "brand": "Sierra" },
      { "name": "GM", "type": "truck", "brand": "Sierra" },
    ];
    
    const deduped = Object.values(vehicles.reduce((o, v) => {
      o[`${v.name}-${v.brand}`] = v;
      return o;
    }, {}));
    
    console.log(deduped);

    If you want to be dynamic with the properties

    const vehicles = [
      { "name": "Ford", "type": "SUV", "brand": "Explorer" },
      { "name": "Ford", "type": "SUV", "brand": "Explorer" },
      { "name": "Ford", "type": "truck", "brand": "F-150" },
      { "name": "Chrysler", "type": "car", "brand": "Sierra" },
      { "name": "GM", "type": "truck", "brand": "Sierra" },
      { "name": "GM", "type": "truck", "brand": "Sierra" },
    ];
    
    const filterOn = ['name', 'brand'];
    
    const deduped = Object.values(vehicles.reduce((o, v) => {
      key = filterOn.map(p => v[p]).join("-");
      o[key] = v; // keeps the last one encountered
      // o[key] = o[key] || v;  // keep just the first one encountered 
      return o;
    }, {}));
    
    console.log(deduped);
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search