Bumblebee
Bumblebee

Reputation: 553

Difference of two javascript arrays of objects

I have two arrays like this:

owners: [
  {
    userID: "58c4d7ac",
    username: "John.Doe",
    firstName: "John",
    lastName: "Doe",
    email: "[email protected]"
  },
  {
    userID: "68c4d7ac",
    username: "User2.Name2",
    firstName: "User2",
    lastName: "Name2",
    email: "[email protected]"
  }
]

users: [
  {
    userID: "58c4d7ac",
    username: "John.Doe",
    firstName: "John",
    lastName: "Doe",
    email: "[email protected]"
  },
  {
    userID: "68c4d7ac",
    username: "User2.Name2",
    firstName: "User2",
    lastName: "Name2",
    email: "[email protected]"
  },
  {
    userID: "88c4d7ac",
    username: "User3.Name3",
    firstName: "User3",
    lastName: "Name3",
    email: "[email protected]"
  }
]

I would like to get an array of users which contains only the elements which are not in the owners array.

I tried different approaches. Finally, I ended up with the solution:

const usersItems = users.map(user => {
    // Check whether the user is already an owner
    if (owners.findIndex(owner => owner.userID === user.userID) === -1) {
        return  owner
    } else {
        return null;
    }
});

console.log(usersItems);

// Filter out all items which are null
const newUsersItems = usersItems.filter(user => {
    if (user) return user;
});

console.log(usersItems);

To me, it doesn't' look like a clean solution. Is there a cleaner and easier way to do this? As a result, I would like to have:

newUsers: [
  {
    userID: "88c4d7ac",
    username: "User3.Name3",
    firstName: "User3",
    lastName: "Name3",
    email: "[email protected]"
  }
]

Upvotes: 1

Views: 84

Answers (7)

Shidersz
Shidersz

Reputation: 17190

First you can create a Set() with the userID's of the owners array, and then you can use Array.filter() on the users array to filter the users whose userID does not belong to the previous created set.

const owners = [
  {userID: "58c4d7ac", username: "John.Doe", firstName: "John", lastName: "Doe", email: "[email protected]"},
  {userID: "68c4d7ac", username: "User2.Name2", firstName: "User2", lastName: "Name2", email: "[email protected]"}
];

const users = [
  {userID: "58c4d7ac", username: "John.Doe", firstName: "John", lastName: "Doe", email: "[email protected]"},
  {userID: "68c4d7ac", username: "User2.Name2", firstName: "User2", lastName: "Name2", email: "[email protected]"},
  {userID: "88c4d7ac", username: "User3.Name3", firstName: "User3", lastName: "Name3", email: "[email protected]"}
];

let ownerIdsSet = new Set(owners.map(x => x.userID));
let res = users.filter(x => !ownerIdsSet.has(x.userID));
console.log(res);
.as-console {background-color:black !important; color:lime;}

But why to construct a Set first?

In summary, it will improve the performance of the filtering process, particularly if the owners array is large. You should note that methods like findIndex(), find() and some() needs to traverse the array for check to the related condition while checking if the userID belongs to the Set is a O(1) calculation. However, of course, there will be an extra overload at initialization to create the mentioned Set.

Upvotes: 2

Ele
Ele

Reputation: 33726

You can use the function some or find, this approach uses the function find

let owners = [   {     userID: "58c4d7ac",     username: "John.Doe",     firstName: "John",     lastName: "Doe",     email: "[email protected]"   },   {     userID: "68c4d7ac",     username: "User2.Name2",     firstName: "User2",     lastName: "Name2",     email: "[email protected]"   } ],
    users = [   {     userID: "58c4d7ac",     username: "John.Doe",     firstName: "John",     lastName: "Doe",     email: "[email protected]"   },   {     userID: "68c4d7ac",     username: "User2.Name2",     firstName: "User2",     lastName: "Name2",     email: "[email protected]"   },   {     userID: "88c4d7ac",     username: "User3.Name3",     firstName: "User3",     lastName: "Name3",     email: "[email protected]"   } ],
    result = users.filter(({userID}) => !owners.find(o => o.userID === userID));

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Upvotes: 0

user3210641
user3210641

Reputation: 1631

You can use combination of filter and some functions like this:

const owners = [
  {
    userID: "58c4d7ac",
    username: "John.Doe",
    firstName: "John",
    lastName: "Doe",
    email: "[email protected]"
  },
  {
    userID: "68c4d7ac",
    username: "User2.Name2",
    firstName: "User2",
    lastName: "Name2",
    email: "[email protected]"
  }
];

const users = [
  {
    userID: "58c4d7ac",
    username: "John.Doe",
    firstName: "John",
    lastName: "Doe",
    email: "[email protected]"
  },
  {
    userID: "68c4d7ac",
    username: "User2.Name2",
    firstName: "User2",
    lastName: "Name2",
    email: "[email protected]"
  },
  {
    userID: "88c4d7ac",
    username: "User3.Name3",
    firstName: "User3",
    lastName: "Name3",
    email: "[email protected]"
  }
];

const result = users.filter(user => !owners.some(owner => owner.userID === user.userID));

console.log(result);

Upvotes: 2

Maxime Girou
Maxime Girou

Reputation: 1570

You can use the reduce function

    const diff = users.reduce((acc, user) => { 
      if(!owners.find(owner => owner.id === user.id){
     acc.push(user);
    }
    return acc;
     }, []);

to avoid use the find() function every loop you can store owner ids in a array with the map an just use includes()

 const ownersIds = owners.map(owner => owner.id);
 const diff = users.reduce((acc, user) => { 
   if(!ownersIds.includes(user.id){
     acc.push(user);
    }
    return acc;
     }, []);

Upvotes: 0

schu34
schu34

Reputation: 985

You could get rid of your map and just use the filter, (that's exactly what filter is for) somthing like

const filtered = users.filter(user => {
    // Check whether the user is already an owner
   return owners.findIndex(owner => owner.userID === user.userID) === -1

}); 

would probably work

Upvotes: 5

mhodges
mhodges

Reputation: 11126

You can just use a single .filter() function, like so:

let owners = [{userID: "58c4d7ac",username: "John.Doe",firstName: "John",lastName: "Doe",email: "[email protected]"},{userID: "68c4d7ac",username: "User2.Name2",firstName: "User2",lastName: "Name2",email: "[email protected]"}];

let users = [{userID: "58c4d7ac",username: "John.Doe",firstName: "John",lastName: "Doe",email: "[email protected]"},{userID: "68c4d7ac",username: "User2.Name2",firstName: "User2",lastName: "Name2",email: "[email protected]"},{userID: "88c4d7ac",username: "User3.Name3",firstName: "User3",lastName: "Name3",email: "[email protected]"}];

let newUsersItems = users.filter(user => owners.findIndex(owner => owner.userID === user.userID) === -1);

console.log(newUsersItems)

You can just use a single .filter() function, like so:

Upvotes: 1

Code Maniac
Code Maniac

Reputation: 37755

You can use filter and some

const owners = [{userID:"58c4d7ac",username:"John.Doe",firstName:"John",lastName:"Doe",email:"[email protected]"},{userID:"68c4d7ac",username:"User2.Name2",firstName:"User2",lastName:"Name2",email:"[email protected]"}]
const users = [{userID:"58c4d7ac",username:"John.Doe",firstName:"John",lastName:"Doe",email:"[email protected]"},{userID:"68c4d7ac",username:"User2.Name2",firstName:"User2",lastName:"Name2",email:"[email protected]"},{userID:"88c4d7ac",username:"User3.Name3",firstName:"User3",lastName:"Name3",email:"[email protected]"}]

const newUsers = users
                .filter(({userID}) => !owners.some(({userID:ownerID})=> ownerID === userID))

console.log(newUsers)

Upvotes: 1

Related Questions