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);