Search code examples
javascriptarraysmultidimensional-array

Comparing 2D-arrays - finding unique items


I have 2 arrays and need to identity the items in array2 that do not occur in array1.

Only the 1st, 2nd and 4th elements should be compared when checking for uniqueness, the 3rd element (amount in stock) should be left out of the comparison.

var array1 = [['892','NEW','2','blue'],
     ['675','USED','2','white'],
     ['943','NEW','2','green'],
     ['121','USED','2','yellow']];

var array2 = [['892','NEW','1','blue'],
     ['892','NEW','1','yellow'],
     ['121','USED','1','blue'],
     ['121','NEW','1','blue'],
     ['121','USED','1','yellow']];

Result should be:

 result = [
     ['892','NEW','1','yellow'],
     ['121','USED','1','blue'],
     ['121','NEW','1','blue']];

I've tried reworking several solutions posted to similar questions but haven't been able to work it out for this specific situation.


Solution

  • You could take a hash table and a function which generates a key out of the given array and filter array2 by checking the hash table.

    function getKey(array) {
        return [0, 1, 3]
            .map(function (i) { return array[i]; })
            .join('|');
    }
    
    var array1 = [['892', 'NEW', '2', 'blue'], ['675', 'USED', '2', 'white'], ['943', 'NEW', '2', 'green'], ['121', 'USED', '2', 'yellow']],
        array2 = [['892', 'NEW', '1', 'blue'], ['892', 'NEW', '1', 'yellow'], ['121', 'USED', '1', 'blue'], ['121', 'NEW', '1', 'blue'], ['121', 'USED', '1', 'yellow']],
        hash = Object.create(null),
        result = [];
    
    array1.forEach(function (a) {
        hash[getKey(a)] = true;
    });
    
    result = array2.filter(function (a) {
        return !hash[getKey(a)];
    });
    
    console.log(result);
    .as-console-wrapper { max-height: 100% !important; top: 0; }

    UPDATE 2023

    With a Set as thisArg for Array#filter.

    const
        array1 = [['892', 'NEW', '2', 'blue'], ['675', 'USED', '2', 'white'], ['943', 'NEW', '2', 'green'], ['121', 'USED', '2', 'yellow']],
        array2 = [['892', 'NEW', '1', 'blue'], ['892', 'NEW', '1', 'yellow'], ['121', 'USED', '1', 'blue'], ['121', 'NEW', '1', 'blue'], ['121', 'USED', '1', 'yellow']],
        getKey = array => [0, 1, 3].map(i => array[i]).join('|'),
        result = array2.filter(
            function (a) { return !this.has(getKey(a)); }, // no arrow for this
            array1.reduce((s, a) => s.add(getKey(a)), new Set)
        );
    
    console.log(result);
    .as-console-wrapper { max-height: 100% !important; top: 0; }