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