简体   繁体   中英

How to get the intersection and symmetric difference of 2 objects in seperate arrays with Javascript

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.

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.

 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);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM