Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Comparing two arrays in Javascript

I've got two arrays in Javascript which currently look like this, but are updated by HTTP requests (node):

var x = [[292,"2349","902103","9"],[3289,"93829","092","920238"]]
var y = [[292,"2349","902103","9"],[322,"93829","092","920238"],[924,"9320","8932","4329"]]

I'm looking to compare these arrays, so that, if there is an array inside y that is not in x, it will be saved to a new array - z. Note that sometimes the order of arrays inside the arrays will change, but I would not like this to affect the result.

If there is an array inside x that is not in y, however, is should not be saved to z.

I read JavaScript array difference and have been able to replicate this, but if the x array is not shown in y, it is printed to z. I am wondering if it is possible for this not to be stored, only the different items in y?

like image 956
GregW Avatar asked Apr 09 '16 17:04

GregW


3 Answers

Use a higher-order function that accepts an array (which changes with each iteration of y) and returns a new function that operates on each element (nested array) in some. It returns true if the arrays contain the same elements regardless of order.

function matches(outer) {
  return function (el) {
    if (outer.length !== el.length) return false;
    return el.every(function (x) {
      return outer.indexOf(x) > -1;
    });
  }
}

Iterate over y and return a list of arrays that aren't in x.

function finder(x, y) {
  return y.filter(function (el) {
    return !x.some(matches(el));
  });
}

finder(x, y);

DEMO

like image 68
Andy Avatar answered Oct 16 '22 05:10

Andy


You can use this function arrayDiff.

It takes two arrays (A and B) and returns an array of all elements that are in the first array and not in the second (A \ B), with any duplicates removed. Two array elements are equal if their JSON serialization is the same.

var x = [[292,"2349","902103","9"],[3289,"93829","092","920238"]];
var y = [[292,"2349","902103","9"],[322,"93829","092","920238"],[924,"9320","8932","4329"]];

var z = arrayDiff(y, x);

// z is [[322,"93829","092","920238"],[924,"9320","8932","4329"]]

// arrayDiff :: [a], [a] -> [a]
function arrayDiff(a1, a2) {
    let a1Set = toStringSet(a1),
        a2Set = toStringSet(a2);

    return Array.from(a1Set)
                .filter(jsonStr => !a2Set.has(jsonStr))
                .map(JSON.parse);

    // toStringSet :: [a] -> Set<String>
    function toStringSet(arr) {
        return new Set(arr.map(JSON.stringify));
    }
}
like image 34
Noah Freitas Avatar answered Oct 16 '22 05:10

Noah Freitas


This should work even if the order in the inner arrays is different.
I'm assuming you will have only numbers and strings in there and you don't expect a strict comparison between them.

var x = [[292,"2349","902103","9"],[3289,"93829","092","920238"]];
var y = [[292,"2349","902103","9"],[322,"93829","092","920238"],[924,"9320","8932","4329"]];

// this will do y \ x
var z = arrDiff(y, x);
console.log(z);


function arrDiff(arr1, arr2) {
  var rez = [];

  for (var i = 0; i < arr1.length; i++) {
    if ( ! contains(arr2, arr1[i])) {
      rez.push(arr1[i]);
    }
  }

  return rez;
}

function contains(arr, x) {
  x = x.slice().sort().toString();
  for (var i = 0; i < arr.length; i++) {
    // compare current item with the one we are searching for        
    if (x === arr[i].slice().sort().toString()) {
      return true;
    }
  }

  return false;
}
like image 36
Mihai Vilcu Avatar answered Oct 16 '22 06:10

Mihai Vilcu