iBlehhz
iBlehhz

Reputation: 586

Retrieve objects in array if property matches another array

I want to create a new array containing contact objects if the value property in contacts matches the values in selectedContact. Any simpler way to do this?

selectedContact: number[] = [0,2] //value
contacts: Contact[] = [{ 
  firstName:"Dan";
  lastName:"Chong";
  email:"[email protected]";
  value:0;
},
{ 
  firstName:"Mark";
  lastName:"Wong";
  email:"[email protected]";
  value:1;
},
{ 
  firstName:"Layla";
  lastName:"Sng";
  email:"[email protected]";
  value: 2;
}]

Intended final result:

newArray = [{ 
 firstName:"Dan";
 lastName:"Chong";
 email:"[email protected]";
 value:0;
},{ 
 firstName:"Layla";
 lastName:"Sng";
 email:"[email protected]";
 value:2;
}];

My current solution:

const newArray: Contact[] = [];
this.selectedContact.forEach(index => {
  newArray.push(this.contacts.find(c => c.value === index));
});

Upvotes: 1

Views: 1306

Answers (2)

lucascaro
lucascaro

Reputation: 19267

In terms of performance, it would be better to iterate over selectedContacts rather than contacts, especially since contacts are indexed (as an array) and you are selecting through the index.

Say the length of contacts is N and the length of selectedContacts is M.

Since selectedContacts is a subset of contacts, we know M <= N. For large databases of contacts, this difference could be significant.

The code in the question:

this.selectedContact.forEach(index => {
  newArray.push(this.contacts.find(c => c.value === index));
});

Has O(M*N) since it iterates over selectedContact O(M) and on each iteration it find a value in contacts (O(N)).

The code from the accepted answer iterates over contact (O(N)) and looks for a value in selectedContact which is O(M). This makes the algorithm equivalent, with O(N*M)

In your example, you already have a cheap way of looking up contacts by number since contacts is an array and your indexes are simply the index in the array.

This means you can use code like this:

return this.selectedContact.map(index => this.contacts[index]);

Since accessing an array element by index has O(1), this would have O(M) which is the smallest of the sizes.

If you can't use the array index as a key, you can use other data structures, like a Map where the id is the key, and the contact is the value. This would have similar lookup speeds (roughly O(1)).

Upvotes: 2

Mamun
Mamun

Reputation: 68933

You can use Array.prototype.filter()

The filter() method creates a new array with all elements that pass the test implemented by the provided function.

and Array.prototype.includes()

The includes() method determines whether an array includes a certain element, returning true or false as appropriate.

Working Code Example:

var selectedContact = [0,2];
var contacts = [{ 
  firstName: "Dan",
  lastName: "Chong",
  email: "[email protected]",
  value: 0
},
{ 
  firstName: "Mark",
  lastName: "Wong",
  email: "[email protected]",
  value: 1
},
{ 
  firstName: "Layla",
  lastName: "Sng",
  email: "[email protected]",
  value: 2
}]
let newArray =  contacts.filter(c => selectedContact.includes(c.value));

console.log(newArray);

Upvotes: 2

Related Questions