user3447653
user3447653

Reputation: 4148

Compare 2 different lists based on 2 columns

I am trying to compare 2 lists based on 2 different columns and get the difference.

const list1 = [[121,"7/2/2019"], [131,"7/22/2019"], [141, ]]
const list2 = [[121, ], [131, ], [141, ]]

In the above 2 lists, I am trying to compare list1 with list2 based on the 2 columns - col1 and col2. First columnn (col1) [121,131,141] will always be the same in both the lists.

For every unique column 1 (col1) [121,131,141] in list1, compare the corresponding element in list2 based on second column, and if it is different, I am trying to output it to a different list

Result = [[121,"7/2/2019"], [131,"7/22/2019"]

Another example is

const list1 = [[121,"7/2/2019"], [131,"7/22/2019"], [141, ]]
const list2 = []

Result = [[121,"7/2/2019"], [131,"7/22/2019"], [141, ]]

I tried with the below code but it does not yield my desired result

const obj1 = list1.reduce((o, e) => Object.assign(o, {[e]: true}), {});
const obj2 = list2.reduce((o, e) => Object.assign(o, {[e]: true}), {});
const list3 = list2.filter(e => !obj1[e]); 
const list4 = list2.concat(list1.filter(e => !obj2[e])); 

Any leads/suggestions would be appreciated.

Upvotes: 0

Views: 105

Answers (3)

Tanaike
Tanaike

Reputation: 201388

As other pattern, for example, how about using Map as follows?

Sample script:

const sample = (list1, list2) => {
  const m = new Map(list2);
  return list1.filter(([a, b]) => !m.has(a) || m.get(a) != b);
}

// Sample pattern 1.
const list1 = [[121, "7/2/2019"], [131, "7/22/2019"], [141,]];
const list2 = [[121,], [131,], [141,]];
const res1 = sample(list1, list2);

// Sample pattern 2.
const list3 = [];
const res2 = sample(list1, list3);

console.log(res1)
console.log(res2)

Note:

  • In above sample script, 2nd element of [141,] is undefined. By this, the output value of this becomes [141]. If you want to output this value as the length of 2, how about modifying above script as follows?

    • From

        return list1.filter(([a, b]) => !m.has(a) || m.get(a) != b);
      
    • To

        return [...new Map(list1)].filter(([a, b]) => !m.has(a) || m.get(a) != b);
      
  • You can test this with the following script.

const sample = (list1, list2) => {
  const m = new Map(list2);
  return [...new Map(list1)].filter(([a, b]) => !m.has(a) || m.get(a) != b);
}

// Sample pattern 1.
const list1 = [[121, "7/2/2019"], [131, "7/22/2019"], [141,]];
const list2 = [[121,], [131,], [141,]];
const res1 = sample(list1, list2);

// Sample pattern 2.
const list3 = [];
const res2 = sample(list1, list3);

console.log(res1)
console.log(res2)

References:

Added:

From your following replying,

If i read the dates from the google sheets, my lists are list1 = [[FH121, Fri Jul 12 00:00:00 GMT-04:00 2019], [FH131, Fri Jul 12 00:00:00 GMT-04:00 2019], [FH141, ]] and list2 = [[FH121, Fri Jul 12 00:00:00 GMT-04:00 2019], [FH131, Fri Jul 12 00:00:00 GMT-04:00 2019], [FH141, Wed Jul 10 00:00:00 GMT-04:00 2019]]. Sample function does not work as it returns all elements in list1 rather than just outputting one element which is [FH141, Wed Jul 10 00:00:00 GMT-04:00 2019]

I couldn't notice that the value of 2nd element in your samples was the date object. This is due to my poor skill. From your replying, I modified above script as follows.

Modified script:

const list1 = [["FH121", new Date("2019-07-12 00:00:00")], ["FH131", new Date("2019-07-12 00:00:00")], ["FH141", ]];
const list2 = [["FH121", new Date("2019-07-12 00:00:00")], ["FH131", new Date("2019-07-12 00:00:00")], ["FH141", new Date("2019-07-10 00:00:00")]];

const m = new Map(list1);
const r = list2.filter(([a, b]) => !m.has(a) || (m.get(a) && m.get(a).getTime()) != (b && b.getTime()));
console.log(r);

Upvotes: 1

Yuri Khristich
Yuri Khristich

Reputation: 14527

If col(1) contains only unique values you can convert the data into an object where col(1) has keys and col(2) has values:

const list1 = [[121,"7/2/2019"], [131,"7/22/2019"], [141, ]];
const list2 = [[121, ], [131, ], [141, ]];

const obj1 = Object.fromEntries(list1);
const obj2 = Object.fromEntries(list2);

var res = [];
for (prop in obj1) {
    if (obj2.hasOwnProperty(prop) && obj2[prop] != obj1[prop]) {
        res.push([prop, obj1[prop]]);
    }
}

console.log(res)

Your another example needs nothing but one line:

if (list2.length == 0) var res = list1;

Upvotes: 1

doubleunary
doubleunary

Reputation: 18784

Try this to compare rows in list1 to the rows in list2 that appear at the same position in their respective arrays:

const difference = list1.filter((row, index) => row[1] !== list2[index][1]);

If the rows are not guaranteed to appear in the same position, try this:

  const list1 = [[121, "7/2/2019"], [131, "7/22/2019"], [141,]];
  const list2 = [[121,], [131,], [141,]];
  const difference = list1.filter((row1, index) => {
    const list2row = list2.filter(row2 => row2[0] === row1[0])[0];
    return !Array.isArray(list2row) || row1[1] !== list2row[1];
  });

Upvotes: 2

Related Questions