0

I am trying to find the difference between two objects based on their keys, the output should be a re-hashed object of the interestion of the two objects with keys maintained, eg:

a[3] = {'data': true};
a[4] = {'data': true};
a[5] = {'data': true};

b[2] = {'data': true};
b[3] = {'data': true};
b[4] = {'data': true};
b[5] = {'data': true};

Outout should be:

[3] = {'data': true};
[4] = {'data': true};
[5] = {'data': true};

So far I have this:

var intersection = a.filter(x => b.includes(x))

I have created the fiddle below, but the result is an empty array:

https://jsfiddle.net/ejtkx6fo/1/

4
  • Please don't link to external code. Your example is small enough to include as a stack snippet. It's also unclear what you are trying to test. Are you checking intersection by index? if so...var intersection = a.filter((x, i) => b[i].data === x.data) Commented Dec 4, 2020 at 10:03
  • Yes intersection by index, but I wish to maintain the index. The example given, like my own, finds the intersection but does not maintain the original keys Commented Dec 4, 2020 at 10:48
  • @mrhr yes sorry that is mis-leading, output should just be an object where the intersecting keys match, the values are not important only the keys Commented Dec 4, 2020 at 10:59
  • 1
    Your output is the intersection not the union. Please either edit the title or the question. Commented Dec 4, 2020 at 13:04

2 Answers 2

1

I just tweaked a little your code and I think this is what you are looking for:

var incoming = [];
var cookie = [];

incoming[3] = {'data': true};
incoming[4] = {'data': true};
incoming[5] = {'data': true};

cookie[2] = {'data': true};
cookie[3] = {'data': true};
cookie[4] = {'data': true};
cookie[5] = {'data': true};

console.log(typeof(cookie));

var x = Object.keys(incoming);
var y = Object.keys(cookie);

var intersection = x.filter(z => y.includes(z))
var result = {}
for (let i of intersection) {
    result[i] = incoming[i]
}
//var intersection = incoming.filter(x => cookie.some(y => x === y))
//var intersection = Object.keys(cookie).filter({}.hasOwnProperty.bind(incoming));
//var intersection = (pred) => (incoming,cookie) => incoming.filter(x => !cookie.some(y => pred(x, y)))

console.log(incoming);
console.log(cookie);
console.log(intersection);
console.log(result);

Look at the console log of result.

Just a little more information on what happens here: If you want to have the keys and the values you should use an object instead of array. The way you are using the arrays you are also creating indexes [0], [1], and [2] with values undefined and this is how javascript works when you use index for array and there are previous indexes that are missing in the mentioned array.

Sign up to request clarification or add additional context in comments.

Comments

1

To compare values it can be as simple as a single map() call, though you'll need to account for differing lengths of the two arrays and customize the return value for unmatched values.

const intersection = a.map((x, i) => b[i].data === x.data ? {...x} : undefined);

const a = [],
  b = [];
  
a[3] = {'data': true};
a[4] = {'data': true};
a[5] = {'data': true};

b[2] = {'data': true};
b[3] = {'data': true};
b[4] = {'data': true};
b[5] = {'data': true};

const intersection = a.map((x, i) => b[i].data === x.data ? {...x} : undefined);

console.log(intersection)


To compare keys you need to access the Object.keys() and compare as needed. Here I am using a some() call to check if any keys don't match.

You'll note that if you add a non-matching key (b[5] = {'data': true, 'id': 1};) this will result in an intersection comparing a to b but not the other direction. (All the keys in a are in b but not all the keys of b are in a);

const a = [],
  b = [];
  
a[3] = {'data': true};
a[4] = {'data': true};
a[5] = {'data': true};

b[2] = {'data': true};
b[3] = {'data': true};
b[4] = {'data': true};
b[5] = {'data': true, 'id': 1};

function intersectByAllKeys(arr1, arr2) {
  return arr1.map((x, i) => {
    const arr2Keys = arr2[i] ? Object.keys(arr2[i]) : [];
    return Object.keys(x).some(k => arr2Keys.indexOf(k) < 0) ? undefined : {...x};
  });
}
console.log(intersectByAllKeys(a, b))

console.log(intersectByAllKeys(b, a))


In order to return a true intersection you will need to compare both directions. Since map() and forEach() skip undefined entries it is simplest to use a for() loop here. Also, since the intersection will never be longer than the shorter of the supplied array we will iterate based on the length of the shorter array (here achieved by destructuring the arguments after sorting const [a, b] = [...arguments].sort((a, b) => (a.length - b.length))).

const a = [],
  b = [];
  
a[3] = {'data': true};
a[4] = {'data': true, 'id': 3};
a[5] = {'data': true};

b[2] = {'data': true};
b[3] = {'data': true};
b[4] = {'data': true, 'id': 0};
b[5] = {'data': true, 'id': 1};

function missingKeys(a, b) {
  return a.some(k => b.indexOf(k) < 0);
}

function intersectSymetricallyByAllKeys(arr1, arr2) {
  const [a, b] = [...arguments].sort((a, b) => (a.length - b.length));
  
  const intersection = [];
  for (let i=0; i<a.length; i++){
    if (!a[i] || !b[i]) {
      intersection[i] = undefined;
    } else {
      const aKeys = Object.keys(a[i]) ?? [];
      const bKeys = Object.keys(b[i]) ?? [];
      
      intersection[i] = missingKeys(aKeys,bKeys) || missingKeys(bKeys,aKeys) ? 
        undefined : {...a[i]}
    }
  }
  
  return intersection;
}

console.log(intersectSymetricallyByAllKeys(a, b));
console.log(intersectSymetricallyByAllKeys(b, a));

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.