0

I have two arrays with "tickets" that I need to update every 3 seconds, the problem is that for animation reasons, I can't simply overwrite the first array to be just like the second.

Like this:

let array_1 = [1, 2, 3, 5]; //diff 3, 5
let array_2 = [1, 2, 6, 7]; //diff 6, 7

What I need is to compare the two arrays, remove "3 and 5" and push "6 and 7" to the first array, leaving the first array as follows:

array_1 = [1, 2, 6, 7];

How to accomplish that?

[EDIT]

For clarification purposes, I'm currently building a dynamic map that receives new info every few seconds, as objects (which is pain in the ass to compare).

I CANNOT have a third array or overwrite the first one, because doing so will cause the markers to 'blink' on the map, so I must manipulate the first one.

I've used @Andrew Yochum response below to came up with the solution as follows:

let array_1 = [
    {serial_number: 'abc', lat: 1, lng: 1},
    {serial_number: 'def', lat: 2, lng: 2},
    {serial_number: 'ghi', lat: 3, lng: 3},
];

let array_2 = [
    {serial_number: 'abc', lat: 1, lng: 1},
    {serial_number: 'def', lat: 2, lng: 2},
    {serial_number: 'jkl', lat: 4, lng: 4},
    {serial_number: 'mno', lat: 5, lng: 5},
];

let compare_1 = JSON.parse(JSON.stringify(array_1));
compare_1 = compare_1.map(el => JSON.stringify(el));

let compare_2 = JSON.parse(JSON.stringify(array_2));
compare_2 = compare_2.map(el => JSON.stringify(el));

let removeArray = [...compare_1.filter(i => !compare_2.includes(i))];
let addArray = [...compare_2.filter(i => !compare_1.includes(i))];

compare_1.forEach((first_el) => {
    removeArray.forEach((second_el) => {
        if(first_el == second_el){
            array_1.splice(compare_1.indexOf(first_el, 1));
        }
    });
});

addArray.forEach((element) => {
    array_1.push(JSON.parse(element));
});

Any way to optimize this?

Community
  • 1
  • 1
Platiplus
  • 107
  • 3
  • 12
  • Already answered on stack overflow https://stackoverflow.com/questions/1584370/how-to-merge-two-arrays-in-javascript-and-de-duplicate-items – Janak Prajapati Apr 23 '19 at 13:38
  • 3
    `array_1 = array_2` ? – Jonas Wilms Apr 23 '19 at 13:39
  • 1
    @ScottStensland isn't it different? in the "duplicate" link, you need to merge two arrays and remove duplicates. In this case, he needs to keep duplicates and get elements from one array only. Besides, isn't the output just the original array? It's **similar**, of course, but not the same task. – briosheje Apr 23 '19 at 13:40
  • Or `array_1.splice(0, array_1.length, ...array_2)` if you want to copy the elements, not overwrite the variable. – Bergi Apr 23 '19 at 13:42
  • @Bergi wouldn't that bring `[1,2,3,5]`? – briosheje Apr 23 '19 at 13:44
  • @briosheje That might be the result of the expression (because that's the items that are removed from `array_1`), but afterwards `array_1` equals `[1, 2, 6, 7]`. – Bergi Apr 23 '19 at 13:48
  • @Bergi yup, you're right, indeed, since splice alters the array. – briosheje Apr 23 '19 at 13:51
  • Can you compare those objects by their `serial_number`? If yes, you should do that instead of anything with JSON. – Bergi Apr 23 '19 at 19:48

3 Answers3

2

Given your new constraints of needing to edit the original array in-place, and the sample data you provided, here is a fairly optimal solution without the JSON encoding/decoding your solution utilizes. No new arrays or copies are made. It also assumes that the serial_number is a unique key that can be used to dedupe between the arrays.

let array_1 = [
    {serial_number: 'abc', lat: 1, lng: 1},
    {serial_number: 'def', lat: 2, lng: 2},
    {serial_number: 'ghi', lat: 3, lng: 3},
]; //diff 'ghi'
let array_2 = [
    {serial_number: 'abc', lat: 1, lng: 1},
    {serial_number: 'def', lat: 2, lng: 2},
    {serial_number: 'jkl', lat: 4, lng: 4},
    {serial_number: 'mno', lat: 5, lng: 5},    
]; //diff 'jkl' 'mno'

function containsSerialNumber(array, serial_number) {
    for(let i = 0; i < array.length; i++) {
        if (array[i].serial_number === serial_number) {
            return true;
        }
    }
}

// removes 'ghi'
for (let i = 0; i < array_1.length; i++) {
    if (!containsSerialNumber(array_2, array_1[i].serial_number)) {
        array_1.splice(i,1);
        i--; // Adjust i down since we just edited in-place
    }
}

// add 'jkl' 'mno'
for (let i = 0; i < array_2.length; i++) {
    if (!containsSerialNumber(array_1, array_2[i].serial_number))
        array_1.push(array_2[i]);
}  
Andrew Yochum
  • 1,056
  • 8
  • 13
  • 1
    As I said earlier, I can't have a new array because it would mess with front-end animations, but I've used part of your answer as I came up with the solution. – Platiplus Apr 23 '19 at 17:29
  • @Platiplus try this new solution given your new constraints – Andrew Yochum Apr 23 '19 at 19:42
  • Wow, looks really promising, but that JSON decoding/encoding it's because I used integers on my example, but the real deal are JSON objects, they are markers on the map, each one is like: {serial_number: "xxx", lat: "1", lng:"1"}, Would that also work on them? – Platiplus Apr 23 '19 at 20:16
  • It can with some adjustment – Andrew Yochum Apr 23 '19 at 20:46
  • Awesome solution, I'll adjust it here to some extra especifications on my end. Thanks a lot! – Platiplus Apr 23 '19 at 20:52
0

let array_1 = [1, 2, 3, 5]; //diff 3, 5
let array_2 = [1, 2, 6, 7]; //diff 6, 7

for(var i = 0; i < array_1.length; i++){
  if(array_1[i] != array_2[i]){
    array_1[i] = array_2[i];
  }
}
console.log(array_1);
Dorian Mazur
  • 514
  • 2
  • 12
0

based on what you said "What I need is to compare the two arrays, remove "3 and 5" and push "6 and 7" to the first array":

let array_1 = [1, 2, 3, 5]; //diff 3, 5
let array_2 = [1, 2, 6, 7]; //diff 6, 7

for(var i = 0; i < array_1.length; i++){

  if(array_1[i] != array_2[i]){
        array_1.splice(i,1,array_2[i]);
  }
}
console.log(array_1);