如果存在则更新或将新元素添加到对象数组 - javascript + lodash中的优雅方式

gan*_*rty 15 javascript arrays underscore.js lodash

所以我有一个像这样的对象数组:

var arr = [
  {uid: 1, name: "bla", description: "cucu"},
  {uid: 2, name: "smth else", description: "cucarecu"},
]
Run Code Online (Sandbox Code Playgroud)

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"}
]
Run Code Online (Sandbox Code Playgroud)

我目前的方式似乎不是很优雅和功能:

function addOrReplace (arr, object) {
  var index = _.findIndex(arr, {'uid' : object.uid});
  if (-1 === index) {
    arr.push(object);
  } else {
    arr[index] = object;
  }
} 
Run Code Online (Sandbox Code Playgroud)

我正在使用lodash,所以我正在考虑_.union使用自定义相等检查修改的内容.

Ing*_*goP 20

如果您不介意最终项目的顺序,那么更简洁的功能性 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}];
Run Code Online (Sandbox Code Playgroud)

如果 item 存在,则会将其排除,然后在末尾添加新的 item,基本上就是替换,如果 item 未找到,则会在末尾添加新对象。

这样你就会有不可变的列表。唯一需要知道的是,如果您要在屏幕上呈现列表,则需要进行某种排序才能保持列表顺序。

希望这对某人有用。


fri*_*edi 11

您可以使用对象而不是数组:

var hash = {
  '1': {uid: 1, name: "bla", description: "cucu"},
  '2': {uid: 2, name: "smth else", description: "cucarecu"}
};
Run Code Online (Sandbox Code Playgroud)

关键是uids.现在你的功能addOrReplace很简单:

function addOrReplace(hash, object) {
    hash[object.uid] = object;
}
Run Code Online (Sandbox Code Playgroud)

UPDATE

除了数组之外,还可以使用对象作为索引.
这样你就可以获得快速查找和工作数组:

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;
}
Run Code Online (Sandbox Code Playgroud)

看看在的jsfiddle-演示(面向对象的解决方案,你会发现这里)


tan*_*y_k 10

在您的第一种方法中,无需借助Lodash findIndex()

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);
}
Run Code Online (Sandbox Code Playgroud)

例:

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'}
]
*/
Run Code Online (Sandbox Code Playgroud)

(1)其他可能的名字:addOrUpdate()upsert()appendOrUpdate()insertOrUpdate()...

(2)也可以用 array.splice(i, 1, item)

请注意,这种方法是“可变的”(相对于“不可变的”):这意味着,它无需修改新数组(无需触摸原始数组),而是直接修改原始数组。大多数时候,这就是您想要的。


pga*_*mou 5

我个人不喜欢修改原始数组/对象的解决方案,所以这就是我所做的:

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)
    ];
}
Run Code Online (Sandbox Code Playgroud)

你会像这样使用它:

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
  })
);
Run Code Online (Sandbox Code Playgroud)

我决定做的是让它更灵活:

  1. 通过 using lodash -> _.findIndex()谓词可以是多个东西
  2. 通过传递 callback getItem(),您可以决定是完全替换该项目还是进行一些修改,就像我在示例中所做的那样。

注意:此解决方案包含一些 ES6 特性,例如解构、箭头函数等。