简体   繁体   中英

Compare 2 Arrays of Objects and Remove Duplicates

I have 2 arrays of objects in JavaScript and would like to compare and merge the contents and sort the results by id. Specifically, the resulting sorted array should contain all objects from the 1st array, plus all objects from the 2nd array that have an id that's not in the 1st.

The following code seems to work (minus the sorting). But there must be a better, more succinct way to do this, particularly with features from ES6. I assume using a Set is the way to go, but not sure exactly how to implement.

 var cars1 = [ {id: 2, make: "Honda", model: "Civic", year: 2001}, {id: 1, make: "Ford", model: "F150", year: 2002}, {id: 3, make: "Chevy", model: "Tahoe", year: 2003}, ]; var cars2 = [ {id: 3, make: "Kia", model: "Optima", year: 2001}, {id: 4, make: "Nissan", model: "Sentra", year: 1982}, {id: 2, make: "Toyota", model: "Corolla", year: 1980}, ]; // Resulting cars1 contains all cars from cars1 plus unique cars from cars2 cars1 = removeDuplicates(cars2); console.log(cars1); function removeDuplicates(cars2){ for (entry in cars2) { var keep = true; for (c in cars1) { if (cars1[c].id === cars2[entry].id) { keep = false; } } if (keep) { cars1.push({ id:cars2[entry].id, make:cars2[entry].make, model:cars2[entry].model, year:cars2[entry].year }) } } return cars1; }

One option with O(N) complexity would be to make a Set of the id s in cars1 , then spread cars1 and a filtered cars2 into the ouput array, with the filter testing whether the id in the car being iterated over in cars2 is included in the Set:

 var cars1 = [ {id: 2, make: "Honda", model: "Civic", year: 2001}, {id: 1, make: "Ford", model: "F150", year: 2002}, {id: 3, make: "Chevy", model: "Tahoe", year: 2003}, ]; var cars2 = [ {id: 3, make: "Kia", model: "Optima", year: 2001}, {id: 4, make: "Nissan", model: "Sentra", year: 1982}, {id: 2, make: "Toyota", model: "Corolla", year: 1980}, ]; const cars1IDs = new Set(cars1.map(({ id }) => id)); const combined = [ ...cars1, ...cars2.filter(({ id }) => !cars1IDs.has(id)) ]; console.log(combined);

To sort as well:

combined.sort(({ id: aId }, {id: bId }) => aId - bId);

 var cars1 = [ {id: 2, make: "Honda", model: "Civic", year: 2001}, {id: 1, make: "Ford", model: "F150", year: 2002}, {id: 3, make: "Chevy", model: "Tahoe", year: 2003}, ]; var cars2 = [ {id: 3, make: "Kia", model: "Optima", year: 2001}, {id: 4, make: "Nissan", model: "Sentra", year: 1982}, {id: 2, make: "Toyota", model: "Corolla", year: 1980}, ]; const cars1IDs = new Set(cars1.map(({ id }) => id)); const combined = [ ...cars1, ...cars2.filter(({ id }) => !cars1IDs.has(id)) ]; combined.sort(({ id: aId }, {id: bId }) => aId - bId); console.log(combined);

You could use concat , filter and map .

 var cars1 = [ {id: 2, make: "Honda", model: "Civic", year: 2001}, {id: 1, make: "Ford", model: "F150", year: 2002}, {id: 3, make: "Chevy", model: "Tahoe", year: 2003}, ]; var cars2 = [ {id: 3, make: "Kia", model: "Optima", year: 2001}, {id: 4, make: "Nissan", model: "Sentra", year: 1982}, {id: 2, make: "Toyota", model: "Corolla", year: 1980}, ]; // Resulting cars1 contains all cars from cars1 plus unique cars from cars2 let ids = cars1.map(c => c.id); cars1 = cars1.concat(cars2.filter(({id}) => !ids.includes(id))) console.log(cars1);

Merge two arrays, put each array element in a map with their ids and then create array from the map values.

 var cars1 = [ {id: 2, make: "Honda", model: "Civic", year: 2001}, {id: 1, make: "Ford", model: "F150", year: 2002}, {id: 3, make: "Chevy", model: "Tahoe", year: 2003}, ]; var cars2 = [ {id: 3, make: "Kia", model: "Optima", year: 2001}, {id: 4, make: "Nissan", model: "Sentra", year: 1982}, {id: 2, make: "Toyota", model: "Corolla", year: 1980}, ]; cars = cars1.concat(cars2); let foo = new Map(); for(const c of cars){ foo.set(c.id, c); } let final = [...foo.values()] console.log(final)

You could take a Map and take the item of them map first or the actual car.

 var cars1 = [{ id: 2, make: "Honda", model: "Civic", year: 2001 }, { id: 1, make: "Ford", model: "F150", year: 2002 }, { id: 3, make: "Chevy", model: "Tahoe", year: 2003 }], cars2 = [{ id: 3, make: "Kia", model: "Optima", year: 2001 }, { id: 4, make: "Nissan", model: "Sentra", year: 1982 }, { id: 2, make: "Toyota", model: "Corolla", year: 1980 }], result = Array .from( [...cars1, ...cars2] .reduce((m, c) => m.set(c.id, m.get(c.id) || c), new Map) .values() ) .sort((a, b) => a.id - b.id); console.log(result);

You can use Object.values() alongwith .concat() and .reduce() :

 let cars1 = [ {id: 2, make: "Honda", model: "Civic", year: 2001}, {id: 1, make: "Ford", model: "F150", year: 2002}, {id: 3, make: "Chevy", model: "Tahoe", year: 2003}, ]; let cars2 = [ {id: 3, make: "Kia", model: "Optima", year: 2001}, {id: 4, make: "Nissan", model: "Sentra", year: 1982}, {id: 2, make: "Toyota", model: "Corolla", year: 1980}, ]; let merge = (arr1, arr2) => Object.values( arr1.concat(arr2).reduce((r, c) => (r[c.id] = r[c.id] || c, r), {}) ).sort((a, b) => a.id - b.id); console.log(merge(cars1, cars2));
 .as-console-wrapper { max-height: 100% !important; top: 0; }

Assuming that the id's should be unique, this should work:

var union = (arr1, arr2) => 
{
    var result = arr1.slice(0);
    arr2.forEach((el) => 
    { 
        if (getIndexByAttribute(arr1, 'id', el.id) < 0)
            result .push(el); 
    });
    return result;
};

var getIndexByAttribute = (array, attr, value) => {
    for(var i = 0; i < array.length; i += 1) {
        if(array[i][attr] === value) {
            return i;
        }
    }
    return -1;
}

But with your current examples cars1 and cars2 , you might need object camparison. Please see Object comparison in JavaScript [duplicate]

One approach can be using concat() with the elements of cars2 whose ids are not already on cars1 , this can be checked using find() . And finally sort() the resulting array:

 var cars1 = [ {id: 2, make: "Honda", model: "Civic", year: 2001}, {id: 1, make: "Ford", model: "F150", year: 2002}, {id: 3, make: "Chevy", model: "Tahoe", year: 2003}, ]; var cars2 = [ {id: 3, make: "Kia", model: "Optima", year: 2001}, {id: 4, make: "Nissan", model: "Sentra", year: 1982}, {id: 2, make: "Toyota", model: "Corolla", year: 1980}, ]; let res = cars1 .concat(cars2.filter(({id}) => !cars1.find(x => x.id === id))) .sort((a, b) => a.id - b.id); console.log(res);
 .as-console {background-color:black !important; color:lime;} .as-console-wrapper {max-height:100% !important; top:0;}

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