I am wondering what is the most efficient way to update an object property that is stored in an array with 10k+ items.
For example if I have an array that holds objects like this {name:"", price:"")
I want to replace or more like update the price values if the array contains that element already.
Check if Array contains object with name = x, if so replace the price with the newest price.
I dont want to have duplicate elements in that array so its not getting to big, i figured I should update it if a property value already exists in it.
So far I have tried several ways like with using indexOf, splice, or just for loops. I am wondering what is the best way performance wise to deal with big arrays.
let array = [
{name:"abc", price: 24},
{name:"cde", price: 25},
{name:"fgh", price: 22},
{name:"gfds", price: 21},
]
function addToArray(elem){
//check if array contains elem by checking for name property value
if(array.filter(el => el.name === elem.name).length > 0){
//update the array element that has the name of the passed elem
}
}
I am wondering what is the most efficient way to update an object property that is stored in an array with 10k+ items.
For example if I have an array that holds objects like this {name:"", price:"")
I want to replace or more like update the price values if the array contains that element already.
Check if Array contains object with name = x, if so replace the price with the newest price.
I dont want to have duplicate elements in that array so its not getting to big, i figured I should update it if a property value already exists in it.
So far I have tried several ways like with using indexOf, splice, or just for loops. I am wondering what is the best way performance wise to deal with big arrays.
let array = [
{name:"abc", price: 24},
{name:"cde", price: 25},
{name:"fgh", price: 22},
{name:"gfds", price: 21},
]
function addToArray(elem){
//check if array contains elem by checking for name property value
if(array.filter(el => el.name === elem.name).length > 0){
//update the array element that has the name of the passed elem
}
}
Share
Improve this question
edited Jan 17, 2022 at 7:51
BitQueen
asked Jan 17, 2022 at 7:45
BitQueenBitQueen
8251 gold badge14 silver badges31 bronze badges
2
- I mean, fundamentally, a simple loop, but the question is quite vague and open-ended. Perhaps if you could give us an example of a few array elements and the changes you want to make to them. – T.J. Crowder Commented Jan 17, 2022 at 7:48
- i thought I gave the element structure already but I edited initial post, does that help? – BitQueen Commented Jan 17, 2022 at 7:51
2 Answers
Reset to default 5You've said your starting point is an array, but the most efficient way to do this is with a Map
, not an array, where the key is the name and the value is either the price or an object containing the price (depending on whether you need other information).
With an Unsorted Array
But if you're doing this with an array, unless we can build / maintain the array in sorted order (see "With a Sorted Array" below), there's nothing more efficient than just looping through it looking for a previous element with the given name
. filter
isn't the right tool for that (you don't need the array it creates). You'd either write your own loop:
let element;
for (let index = 0, length = array.length; index < length; ++index) {
const thisElement = array[index];
if (thisElement.name === name) {
// Already have one
element = thisElement;
break;
}
}
if (element) {
element.price += price;
} else {
array.push({name, price});
}
With some JavaScript engines, you might get just that teensy bit more speed if you declared index
, length
, and thisElement
before the loop:
let element, index, length, thisElement;
for (index = 0, length = array.length; index < length; ++index) {
thisElement = array[index];
// ...
but with others it could be the opposite. (It's not likely to be a big difference either way.)
Or use find
:
const element = array.find(e => e.name === name);
if (element) {
element.price += price;
} else {
array.push({name, price});
}
Either of those provides linear lookup time. But if you were using a Map
, you'd get sublinear lookup time.
With a Map
If using an object as the value:
const element = map.get(name);
if (element) {
element.price += price;
} else {
map.set(name, {name, price});
}
Or if using the price as the value:
const currentPrice = map.get(name) ?? 0; // If not found, `get` returns undefined; convert it to 0
map.set(currentPrice + price);
With a Sorted Array
If we can build / maintain the array in sorted order (you've said you can't, but maybe others finding this later can), we can do better than linear lookup by using a binary search (at the cost of slightly more overhead when inserting a new element, because all the ones after the insertion point have to be moved). It's more code, but if the search time is the main issue, it cuts search time.
const upsert = (array, name, price) => {
let left = 0;
let right = array.length;
while (left < right) {
let guess = Math.floor((left + right) / 2);
let element = array[guess];
if (element.name === name) {
// Found! Update it
element.price += price;
return;
}
if (element.name < name) {
left = guess + 1;
} else {
right = guess - 1;
}
}
// Not found, insert it
array.splice(left, 0, {name, price});
};
For ONE name, use find:
let array = [
{name:"abc", price: 24},
{name:"cde", price: 25},
{name:"fgh", price: 22},
{name:"gfds", price: 21},
]
const elem = array.find(({name}) => name==='fgh');
if (elem) elem.price = "40";
console.log(array);