Home > Back-end >  Make objects in an array unique depending on multiple subkeys
Make objects in an array unique depending on multiple subkeys

Time:01-08

I found this example on

https://blog.adriaan.io/make-array-with-objects-unique-on-multiple-keys-in-javascript.html

const browsers = [ 
    { os: "OS X", 
        os_version: "Catalina", 
        browser: "chrome", 
        browser_version: "30.0" 
    }, 
    { 
        os: "Windows", 
        os_version: "7", 
        browser: "chrome", 
        browser_version: "40.0" 
    }, 
    { 
        os: "Windows", 
        os_version: "7", 
        browser: "chrome", 
        browser_version: "50.0" 
    } 
]; 


const makeUnique = (array = [], keys = []) => { 
    if (!keys.length || !array.length) return []; 
    
    return array.reduce((list, item) => { 
        const hasItem = list.find(listItem => keys.every(key => listItem[key] === item[key]) ); 
        if (!hasItem) list.push(item); 
        return list; 
    },[]); 
}; 


console.log(makeUnique(browsers, ["os", "os_version"]));

I would like to use this with my objectarray but i use keys in a key. Does anyone know how to adapt the method to my example in order to ignore double bounds?


const tiles = [
    {
        name: "pattern1",
        type: "jpg",
        size: 1024,
        bounds:{topleft_x: 45, topleft_y: 45, downright_x: -45, downright_y: -45},
    },
        name: "pattern2",
        type: "jpg",
        size: 1024,
        bounds:{topleft_x: 90, topleft_y: 90, downright_x: 45, downright_y: 45},
    },
        name: "pattern3",
        type: "jpg",
        size: 1024,
        bounds:{topleft_x: 45, topleft_y: 45, downright_x: -45, downright_y: -45},
    },
    //...
];

CodePudding user response:

you need a traverse function this function gets an object and a string called path, path is something like bounds.topleft_y

function traverse(obj, path) {
    if (!path.includes('.')) return obj[path];
    return path.split('.').reduce((a, k) => a[k], obj)
}

and you need to change makeUnique function

const makeUnique = (array = [], keys = []) => {
    if (!keys.length || !array.length) return []; 

    return array.reduce((list, item) => {
        const hasItem = list.find(listItem => keys.every(key => traverse(listItem, key) === traverse(item, key)));
        console.log(data, item, hasItem)
        if (!hasItem) list.push(item);
        return list;
    }, [])
}

and here is how you can use it

makeUnique(data, ['type', 'bounds.topleft_y'])

CodePudding user response:

The crux of any deduping algorithm is how equality is determined. In the example algorithm you provided, that occurs with checking listItem[key] === item[key]. Strict equality (===) works great for comparing primitive values, but there is no built-in way to compare objects (like bounds). Therefore, you have to use a custom value equality function.

There is a great npm package called value-equal that does this for you. You can also view its implementation here.

Once you have a valueEqual() function, you can swap it into the algorithm like so:

const makeUnique = (array = [], keys = []) => { 
    if (!keys.length || !array.length) return []; 
    
    return array.reduce((list, item) => { 
        const hasItem = list.find(listItem => keys.every(key => valueEqual(listItem[key], item[key]))); 
        if (!hasItem) list.push(item); 
        return list; 
    },[]); 
}; 

Then you can invoke the algorithm as before:

console.log(makeUnique(tiles, ["type", "bounds"]));
  • Related