Skip to content
Advertisement

JavaScript: Filter object, keeping unique properties

I have an object that I need to filter against and return a new object. The goal is to get all ids that contain “A” in val, BUT only include ids with a unique val.

Below is what I’m currently doing, but I wonder if there’s a more efficient way to do this. As can be seen when you run the code snippet, the new object should look like this:

{
  "id1": {
    "val": "AAA"
  },
  "id4": {
    "val": "ABC"
  }
}

const obj = {
  id1: {
    val: 'AAA',
  },
  id2: {
    val: 'BBB',
  },
  id3: {
    val: 'AAA',
  },
  id4: {
    val: 'ABC',
  },
};

// Filtered object
const obj2 = {};
let matched = '';

for (const key in obj) {
  if (matched.indexOf(obj[key].val) < 0 && obj[key].val.indexOf('A') > -1) {
    obj2[key] = obj[key];
    matched += obj[key].val + ' ';
  }
}

console.log(obj2);

Advertisement

Answer

Instead of building up a string for matched, you should use a Set (O(1) string comparisons for each operation instead of searching an increasingly long string in time proportional to the length of that string – and not running into issues with keys that contain spaces). includes is also a nice modern alternative to indexOf(…) > -1, although not faster.

Also, when using objects to store key/value mappings, you should use prototypeless objects – starting from Object.create(null) – to avoid setter weirdness (mostly __proto__) and tempting but fragile methods (name collisions with Object.prototype), and as a matter of good practice even when that isn’t a concern. Or just use Maps instead.

const obj = {
  id1: {val: 'AAA'},
  id2: {val: 'BBB'},
  id3: {val: 'AAA'},
  id4: {val: 'ABC'},
};

// Filtered object
const obj2 = Object.create(null);
const matched = new Set();

for (const key in obj) {
  if (!matched.has(obj[key].val) && obj[key].val.includes('A')) {
    obj2[key] = obj[key];
    matched.add(obj[key].val);
  }
}

console.log(obj2);
User contributions licensed under: CC BY-SA
10 People found this is helpful
Advertisement