所以我有一个像这样的对象数组:
var arr = [
{uid: 1, name: "bla", description: "cucu"},
{uid: 2, name: "smth else", description: "cucarecu"},
]
uid
是此数组中对象的唯一ID。如果我们拥有给定uid,
的对象或添加新元素,如果数组中不存在所呈现的uid
,我正在寻找修改对象的优雅方法。我想这个函数在js控制台中表现得像那样:
> addOrReplace(arr, {uid: 1, name: 'changed name', description: "changed description"})
> arr
[
{uid: 1, name: "bla", description: "cucu"},
{uid: 2, name: "smth else", description: "cucarecu"},
]
> addOrReplace(arr, {uid: 3, name: 'new element name name', description: "cocoroco"})
> arr
[
{uid: 1, name: "bla", description: "cucu"},
{uid: 2, name: "smth else", description: "cucarecu"},
{uid: 3, name: 'new element name name', description: "cocoroco"}
]
我目前的方式似乎并不优雅和实用:
function addOrReplace (arr, object) {
var index = _.findIndex(arr, {'uid' : object.uid});
if (-1 === index) {
arr.push(object);
} else {
arr[index] = object;
}
}
我正在使用lodash,所以我正在考虑使用自定义相等性检查修改_.union
之类的东西。
答案 0 :(得分:9)
您可以使用对象而不是数组:
var hash = {
'1': {uid: 1, name: "bla", description: "cucu"},
'2': {uid: 2, name: "smth else", description: "cucarecu"}
};
密钥是uid 。现在你的函数addOrReplace
很简单:
function addOrReplace(hash, object) {
hash[object.uid] = object;
}
<强>更新强>
除了数组之外,还可以将对象用作索引。
通过这种方式,您可以获得快速查找以及工作数组:
var arr = [],
arrIndex = {};
addOrReplace({uid: 1, name: "bla", description: "cucu"});
addOrReplace({uid: 2, name: "smth else", description: "cucarecu"});
addOrReplace({uid: 1, name: "bli", description: "cici"});
function addOrReplace(object) {
var index = arrIndex[object.uid];
if(index === undefined) {
index = arr.length;
arrIndex[object.uid] = index;
}
arr[index] = object;
}
看一下 jsfiddle-demo (面向对象的解决方案,你会发现here)
答案 1 :(得分:7)
在您的第一种方法中,由于findIndex()
而无需Lodash:
function addOrReplace(array, item) { // (1)
const i = array.findIndex(_item => _item.id === item.id);
if (i > -1) array[i] = item; // (2)
else array.push(item);
}
示例:
const array = [
{id: 0, name: 'Apple', description: 'fruit'},
{id: 1, name: 'Banana', description: 'fruit'},
{id: 2, name: 'Tomato', description: 'vegetable'}
];
addOrReplace(array, {id: 2, name: 'Tomato', description: 'fruit'})
console.log(array);
/* =>
[
{id: 0, name: 'Apple', description: 'fruit'},
{id: 1, name: 'Banana', description: 'fruit'},
{id: 2, name: 'Tomato', description: 'fruit'}
]
*/
addOrReplace(array, {id: 3, name: 'Cucumber', description: 'vegetable'})
console.log(array);
/* =>
[
{id: 0, name: 'Apple', description: 'fruit'},
{id: 1, name: 'Banana', description: 'fruit'},
{id: 2, name: 'Tomato', description: 'fruit'},
{id: 3, name: 'Cucumber', description: 'vegetable'}
]
*/
(1)其他可能的名称:addOrUpdate()
,upsert()
,appendOrUpdate()
,insertOrUpdate()
......
(2)也可以使用array.splice(i, 1, item)
请注意,这种方法是“可变的”(vs“不可变”):它意味着不是返回一个新数组(不触及原始数组),而是直接修改原始数组。大多数时候,这就是你想要的。
答案 2 :(得分:4)
旧帖子,但为什么不使用过滤功能?
// If you find the index of an existing uid, save its index then delete it
// --- after the filter add the new object.
function addOrReplace( argh, obj ) {
var index = -1;
argh.filter((el, pos) => {
if( el.uid == obj.uid )
delete argh[index = pos];
return true;
});
// put in place, or append to list
if( index == -1 )
argh.push(obj);
else
argh[index] = obj;
}
这是jsfiddle,展示了它是如何运作的。
答案 3 :(得分:3)
也许
_.mixin({
mergeById: function mergeById(arr, obj, idProp) {
var index = _.findIndex(arr, function (elem) {
// double check, since undefined === undefined
return typeof elem[idProp] !== "undefined" && elem[idProp] === obj[idProp];
});
if (index > -1) {
arr[index] = obj;
} else {
arr.push(obj);
}
return arr;
}
});
和
var elem = {uid: 3, name: 'new element name name', description: "cocoroco"};
_.mergeById(arr, elem, "uid");
答案 4 :(得分:1)
让数组的索引与uid
?相同,如:
arr = [];
arr[1] = {uid: 1, name: "bla", description: "cucu"};
arr[2] = {uid: 2, name: "smth else", description: "cucarecu"};
这样你就可以简单地使用
arr[affectedId] = changedObject;
答案 5 :(得分:1)
我个人不喜欢修改原始数组/对象的解决方案,所以这就是我所做的:
function addOrReplaceBy(arr = [], predicate, getItem) {
const index = _.findIndex(arr, predicate);
return index === -1
? [...arr, getItem()]
: [
...arr.slice(0, index),
getItem(arr[index]),
...arr.slice(index + 1)
];
}
您将像这样使用它:
var stuff = [
{ id: 1 },
{ id: 2 },
{ id: 3 },
{ id: 4 },
];
var foo = { id: 2, foo: "bar" };
stuff = addOrReplaceBy(
stuff,
{ id: foo.id },
(elem) => ({
...elem,
...foo
})
);
我决定要做的是使其更加灵活:
lodash -> _.findIndex()
,谓词可以是多个事物getItem()
,您可以决定是完全替换商品还是进行某些修改,就像我在示例中所做的那样。注意:此解决方案包含一些ES6功能,例如解构,箭头功能等。
答案 6 :(得分:0)
如果您不介意最终项目的顺序,那么更简洁的功能 es6 方法如下:
function addOrReplace(arr, newObj){
return [...arr.filter((obj) => obj.uid !== newObj.uid), {...newObj}];
}
// or shorter one line version
const addOrReplace = (arr, newObj) => [...arr.filter((o) => o.uid !== newObj.uid), {...newObj}];
如果item存在则排除然后在最后添加新的item,基本上就是replace,如果没有找到item会在最后添加新的object。
这样你就有了不可变的列表。 唯一需要知道的是,如果您要在屏幕上渲染列表,则需要进行某种排序以保持列表顺序。
希望这对某人有用。