当我运行这个例子时,我希望elementThatAllreadyExist
用名称test1
覆盖现有对象,它正确地做到了。
当我用arr2
运行示例时,我希望newElement
元素被添加到数组中,因为数组中不存在具有name
"test33"
的对象,但没有元素被添加到数组中。
为什么它忽略了我的|| obj
回退?
let arr = [{
name: "test1",
values: {
value1: 1,
value2: 2,
value3: 3,
}
},
{
name: "test2",
values: {
value1: 1,
value2: 2,
value3: 3,
}
},
{
name: "test3",
values: {
value1: 1
}
},
{
name: "test4",
values: {
value1: 1,
value2: 2,
value3: 3,
}
}
]
let elementThatAllreadyExists = [{
name: "test1",
values: {
value1: 3323,
value2: 2323,
value3: 2323,
}
}]
let newElement = [{
name: "test33",
values: {
value1: 666,
value2: 666,
value3: 663,
}
}]
const arr1 = arr.map(obj => newElement.find(o => o.name === obj.name) || obj);
console.log(arr1)
const arr2 = arr.map(obj => elementThatAllreadyExists.find(o => o.name === obj.name) || obj);
console.log(arr2)
将我的评论转换为答案,当.find()
为arr
中的每个元素返回null时,就像newElement
一样,然后|| obj
回退分支为每个元素运行,map
返回浅拷贝。所以它根本没有忽略|| obj
。事实上,这就是它所做的(当元素不存在时)。
map
不添加元素,它转换现有的元素。你可以使用push
。
作为题外话,newElement
和elementThatAllreadyExists
作为一个元素的数组是奇怪的。如果这些变量名应该是数组,那么它们应该是复数形式的。如果它们是单数,则删除数组以使它们成为普通对象。在所有你不打算重新赋值的变量声明上使用const
(这应该是几乎所有的)。
这是函数。如果您的输入确实是数组,则循环遍历它们并调用addOrReplaceExisting
函数,但要注意时间复杂度是二次的。您可能希望使用Map
或由name
键控的对象。.set()
方法已经实现了"replace或"行为,在键上实现唯一性。对于查找和替换,映射是0(1)。
const replaceOrAdd = (arr, el, key="name") => {
const existingIndex = arr.findIndex(e => e[key] === el[key]);
if (existingIndex >= 0) {
arr[existingIndex] = el;
}
else {
arr.push(el);
}
};
const arr = [{ name: "test1", values: { value1: 1, value2: 2, value3: 3, } }, { name: "test2", values: { value1: 1, value2: 2, value3: 3, } }, { name: "test3", values: { value1: 1 } }, { name: "test4", values: { value1: 1, value2: 2, value3: 3, } } ];
const elementThatAlreadyExists = { name: "test1", values: { value1: 3323, value2: 2323, value3: 2323, } };
const newElement = { name: "test33", values: { value1: 666, value2: 666, value3: 663, } };
replaceOrAdd(arr, elementThatAlreadyExists);
replaceOrAdd(arr, newElement);
console.log(arr);
Immuable版本:
const replaceOrAdd = (arr, el, key="name") => {
const existingIndex = arr.findIndex(e => e[key] === el[key]);
if (existingIndex >= 0) {
return Object.freeze([
...arr.slice(0, existingIndex),
el,
...arr.slice(existingIndex + 1),
]);
}
return Object.freeze(arr.concat(el));
};
const arr = Object.freeze([{ name: "test1", values: { value1: 1, value2: 2, value3: 3, } }, { name: "test2", values: { value1: 1, value2: 2, value3: 3, } }, { name: "test3", values: { value1: 1 } }, { name: "test4", values: { value1: 1, value2: 2, value3: 3, } } ]);
const elementThatAlreadyExists = { name: "test1", values: { value1: 3323, value2: 2323, value3: 2323, } };
const newElement = { name: "test33", values: { value1: 666, value2: 666, value3: 663, } };
const arr1 = replaceOrAdd(arr, elementThatAlreadyExists);
const arr2 = replaceOrAdd(arr1, newElement);
console.log(arr2);
Map
version:
const arr = [{ name: "test1", values: { value1: 1, value2: 2, value3: 3, } }, { name: "test2", values: { value1: 1, value2: 2, value3: 3, } }, { name: "test3", values: { value1: 1 } }, { name: "test4", values: { value1: 1, value2: 2, value3: 3, } } ];
const elementThatAlreadyExists = { name: "test1", values: { value1: 3323, value2: 2323, value3: 2323, } };
const newElement = { name: "test33", values: { value1: 666, value2: 666, value3: 663, } };
const elemsByName = new Map(arr.map(e => [e.name, e]));
elemsByName.set(
elementThatAlreadyExists.name,
elementThatAlreadyExists
);
elemsByName.set(newElement.name, newElement);
console.log([...elemsByName.values()]); // or use .get to get a single element by name