您说过您的起点是一个数组,但最有效的方法是使用Map,不是数组,其中键是名称,值是价格或包含价格的对象(取决于您是否需要其他信息)。
使用未排序的数组
但如果你用数组来做这件事,unless我们可以按排序顺序构建/维护数组(请参阅下面的“使用排序数组”),没有什么比循环遍历它查找具有给定值的前一个元素更有效的了name
. filter
不是正确的工具(您不需要它创建的数组)。您可以编写自己的循环:
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});
}
使用某些 JavaScript 引擎,您可能会得到这样的结果teensy如果你声明的话速度会快一点index
, length
, and thisElement
循环之前:
let element, index, length, thisElement;
for (index = 0, length = array.length; index < length; ++index) {
thisElement = array[index];
// ...
但对其他人来说,情况可能恰恰相反。 (无论哪种方式都不太可能有很大的区别。)
Or use find:
const element = array.find(e => e.name === name);
if (element) {
element.price += price;
} else {
array.push({name, price});
}
其中任何一个都提供线性查找时间。但如果你使用的是Map
,你会得到亚线性查找时间。
带地图
如果使用对象作为值:
const element = map.get(name);
if (element) {
element.price += price;
} else {
map.set(name, {name, price});
}
或者如果使用价格作为价值:
const currentPrice = map.get(name) ?? 0; // If not found, `get` returns undefined; convert it to 0
map.set(currentPrice + price);
使用排序数组
如果我们可以按排序顺序构建/维护数组(你说过你不能,但也许其他人稍后发现可以),我们可以通过使用二分搜索比线性查找做得更好(代价是slightly插入新元素时会产生更多开销,因为插入点之后的所有元素都必须移动)。这是更多的代码,但如果搜索时间是主要问题,它会减少搜索时间。
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});
};