Reputation: 928
It seems weird that this isn't an duplicate, but I cant find what I want so here is what I want:
I have 2 arrays. array 1 is new data I reveived from an API. array 2 is old data I recieved from my database.
I want to filter out the items from array 1 that are equal to the items in array 2 (by id), and collect them in my alreadyExist array. Also I want to filter out the items from array 1 that do not exist in object 2 (new items). And the items from object 2 that do not exist in object 1 (removed items). I collect these all in seperate arrays. So a alreadyExist, new and removed array.
Long short, I want the intersection and symmetric difference of 2 objects in seperate arrays in the fastest way possible because I use alot of data.
My api can give me a array of 200.000+ objects with each 65 fields in it. My database can give me a 200.000+ objects with each 25 fields.
I have the intersection.
This is my code:
let itemAlreadyExistArray = [];
// Final object its fields.
let finalObject = {
id: null,
field2: null,
field3: null,
field4: null,
objectName: null
password: null
}
// Get each item in array1.
for (var i = 0; i < array1.length; i++) {
// Get each item in array2.
for (var j = 0; j < array2.length; j++) {
// Check if already exists (intersection part)
if (array1[i].id == array2[j].id) {
finalObject.id = array1[i].id;
finalObject.field2 = array1[i].id;
finalObject.field3 = array1[i].id;
finalObject.field4 = array1[i].id;
finalObject.objectName = array1[i].id;
finalObject.password= array2[j].id; // From another array.
// Add item.
itemAlreadyExistArray.push(finalObject);
// Better for speed performance.
break;
}
// If there is no id matching then means its either new or removed.
if (j == (array2- 1)) {
// ?????
}
}
}
This is my array data, its fake but lookd the same as mine:
// From DB
array1 [
object1 {
id: "982AD74234",
field2: null,
field3: "85414090",
field4: "AWHDAWDAdadsd",
password: myFirstPassword
},
object2 {
id: "98D3354daw4",
field2: null,
field3: "85414090",
field4: "AWHDAWDAdadsd",
password: mySecondPassword
}
]
//From API
array2 [
object1 {
id: "533da657sd68",
field2: null,
field3: "85414090",
field4: "AWHDAWDAdadsd",
objectName: "some Object 1"
},
object2 {
id: "5345hta346",
field2: null,
field3: "85414090",
field4: "AWHDAWDAdadsd",
objectName: "some Object 2"
},
object3 { // Equal to array1-object 1
id: "982AD74234",
field2: null,
field3: "85414090",
field4: "AWHDAWDAdadsd",
objectName: "some Object 3"
},
object4 {
id: "9827js4233544",
field2: null,
field3: "85414090",
field4: "AWHDAWDAdadsd",
objectName: "some Object 4"
}
]
Also I have to change the data inside the objects of array1 and array2 and merge some fields together.
So with the example above I need to be able to have this array with objects when the object id's match (intersection): I merged the password I got from my database with the objectName I got from my API into one object with some other standard data.
Also note: ID's can have numbers and letters!
alreadyExists [
object3 { // Equal to array1-object1
id: "982AD74234",
field2: null,
field3: "85414090",
field4: "AWHDAWDAdadsd",
objectName: "some Object 3"
password: myFirstPassword //Merged from array1-object1
}
]
When I need to check if an object is new or removed I use some standard object data. So then it does not need to be changed/merged.
Upvotes: 0
Views: 200
Reputation: 790
I have a dirty hands approach rather than a JavaScript-cool-predefined-prototype-usage one, but you can do it in roughly 4 array crosses, regardless the length.
const array1 = [{ id: 1 },{ id: 2 },{ id: 3 },{ id: 4 },{ id: 5 }];
const array2 = [{ id: 1 },{ id: 4 },{ id: 7 },{ id: 8 },{ id: 5 }];
const array1Dic = {}; // Mapping of id - object having that id
const commonDic = {}; // Mapping of id - object (making note of the common elements)
let array1Different = [];
const array2Different = [];
let common = [];
// Populate first dictionary - one iteration
array1.forEach(item => array1Dic[item.id] = item);
// Populate array2Different and commonDic - one iteration (NO OBJECT MERGE)
array2.forEach(item => !!array1Dic[item.id] ? (commonDic[item.id] = item) : (array2Different.push(item)));
// OR if you need merged common objects
// array2.forEach(item => !!array1Dic[item.id] ? (commonDic[item.id] = { ...item, ...array1Dic[item.id] }) : (array2Different.push(item)));
// Get array1Different using commonDic - one iteration
array1Different = array1.filter(item => !commonDic[item.id]);
common = Object.values(commonDic);
console.log(array1Different);
console.log(array2Different);
console.log(common);
Explanation:
Turning arrays into dictionaries (or dictionary-like objects) can insanely improve performance because there's no more array search for elements, but rather IDs for O(1) search.
I have turned one of the arrays into a dictionary, then iterated through the second one while constantly checking if the current element is in the above dictionary.
If yes, then it's a common element. If no, then it's distinct and belongs to the second array.
Then, I have iterated through the first one again while checking elements with the common
dictionary and filter
-ed out the ones that are common, thus getting the distinct elements belonging to first array.
Common elements are stored in the common
dictionary.
Edit: For object merge you can use the Spread operator to combine the properties of both objects. Check the code above for an example.
Upvotes: 2
Reputation: 5858
let prev_data = [
{
id : 1,
title: 'prev title 1'
},
{
id : 2,
title: 'prev title 2'
},
{
id : 3,
title: 'prev title 3'
},
]
let current_data = [
{
id : 1,
title: 'prev title 1 changed'
},
{
id : 2,
title: 'prev title 2'
},
{
id : 3,
title: 'new title 3'
},
]
// whole of object comparison.
let difference = current_data.filter(i=>!prev_data.some(p=>JSON.stringify(p)===JSON.stringify(i)));
let intersection = current_data.filter(i=>prev_data.some(p=>JSON.stringify(p)===JSON.stringify(i)));
console.log(difference);
console.log(intersection);
// limited attributes comparison if there is too many attr:
let differ = current_data.filter(i=>!prev_data.some(p=>p.id===i.id && p.title===i.title));
console.log(differ);
Upvotes: 0