如果存在,请更新或向对象数组添加新元素 - javascript + lodash 中的优雅方式
Update if exists or add new element to array of objects - elegant way in javascript + lodash
所以我有这样的对象数组:
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
之类的东西。
在您的第一种方法中,由于findIndex()
,不需要 Lodash :
function upsert(array, element) { // (1)
const i = array.findIndex(_element => _element.id === element.id);
if (i > -1) array[i] = element; // (2)
else array.push(element);
}
例:
const array = [
{id: 0, name: 'Apple', description: 'fruit'},
{id: 1, name: 'Banana', description: 'fruit'},
{id: 2, name: 'Tomato', description: 'vegetable'}
];
upsert(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'}
]
*/
upsert(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(其他可能的名称:addOrReplace()
、addOrUpdate()
、appendOrUpdate()
、insertOrUpdate()
...
(2(也可以用array.splice(i, 1, element)
请注意,这种方法是"可变的"(相对于"不可变的"(:这意味着它不是返回一个新数组(不接触原始数组(,而是直接修改原始数组。
您可以使用对象而不是数组:
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(一个面向对象的解决方案,你可以在这里找到(
如果您不介意最后项目的顺序,那么更简洁的功能 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}];
如果项目存在,它将被排除,然后在末尾添加新项目,基本上它是替换的,如果项目没有找到,将在最后添加新对象。
这样,您将拥有不可变的列表。唯一要知道的是,例如,如果您在屏幕上呈现列表,则需要进行某种排序以保持列表顺序。
希望这对某人来说很方便。
我个人不喜欢修改原始数组/对象的解决方案,所以我就是这样做的:
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 功能,例如解构、箭头函数等。
<小时 />对此还有第二种方法。我们可以使用 JavaScript Map 对象,它"保存键值对并记住键的原始插入顺序"加上"任何值(对象和基元值(都可以用作键或值"。
let myMap = new Map(
['1', { id: '1', first: true }] // key-value entry
['2', { id: '2', second: true }]
)
myMap = new Map([
...myMap,
['1', { id: '1', first: true, other: '...' }]
['3', { id: '3', third: true }]
])
myMap
将按顺序包含以下条目:
['1', { id: '1', first: true, other: '...' }]
['2', { id: '2', second: true }]
['3', { id: '3', third: true }]
我们可以利用地图的这个特性来添加或替换其他元素:
function addOrReplaceBy(array, value, key = "id") {
return Array.from(
new Map([
...array.map(item => [ item[key], item ]),
[value[key], value]
]).values()
)
}
也许
_.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");
旧帖子,但为什么不使用过滤功能?
// 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。
非常复杂的解决方案:D这是一个行:
const newArray = array.filter(obj => obj.id !== newObj.id).concat(newObj)
的索引与uid
相同呢?,例如:
arr = [];
arr[1] = {uid: 1, name: "bla", description: "cucu"};
arr[2] = {uid: 2, name: "smth else", description: "cucarecu"};
这样你就可以简单地使用
arr[affectedId] = changedObject;
Backbone.Collection
恰恰提供了此功能。尽可能节省自己的精力!
var UidModel = Backbone.Model.extend({
idAttribute: 'uid'
});
var data = new Backbone.Collection([
{uid: 1, name: "bla", description: "cucu"},
{uid: 2, name: "smth else", description: "cucarecu"}
], {
model: UidModel
});
data.add({uid: 1, name: 'changed name', description: "changed description"}, {merge: true});
data.add({uid: 3, name: 'new element name name', description: "cocoroco"});
console.log(data.toJSON());
- 如何找到Javascript元素的最长边
- 如何通过它瞄准javascript元素's的onclick属性
- Javascript元素相对于屏幕的位置
- 找不到javascript元素
- JavaScript元素遍历返回的值超出预期
- 没有获得基础's的Javascript元素工作(与Laravel和Elixir)
- 为什么在ASP.NET Ajax更新面板中执行任何操作后javascript元素都停止工作
- 将 JavaScript 元素 ID 传递给 PHP 或 Form Variable
- Javascript元素相互阻塞
- CefSharp javascript元素点击不;不起作用,但手动点击它可以
- javascript元素.click()发布Safari
- Javascript元素更新侦听器
- Javascript 元素值的总和
- 在 php 代码中调用 javascript 元素
- If-Statement中的Javascript元素验证
- JavaScript 元素识别和检索
- 单击内部锚点/哈希时自动更新 JavaScript 元素
- 将 JavaScript 元素作为变量传递
- 按下表单重置按钮时删除 JavaScript 元素
- 将 javascript 保留在新的 JavaScript 元素中