簡體   English   中英

如果存在則更新或向對象數組添加新元素 - 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,或者添加一個新元素,如果數組中不存在呈現的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, 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'}
];

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, item)

請注意,這種方法是“可變的”(相對於“不可變的”):它意味着不是返回一個新數組(不接觸原始數組),而是直接修改原始數組。

您可以使用對象而不是數組

var hash = {
  '1': {uid: 1, name: "bla", description: "cucu"},
  '2': {uid: 2, name: "smth else", description: "cucarecu"}
};

鍵是 uids 現在您的函數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 (你可以在這里找到一個面向對象的解決方案)

我個人不喜歡修改原始數組/對象的解決方案,所以這就是我所做的:

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
  })
);

我決定做的是讓它更靈活:

  1. 通過使用lodash -> _.findIndex()謂詞可以是多個東西
  2. 通過傳遞回調getItem() ,您可以決定是完全替換該項目還是進行一些修改,就像我在示例中所做的那樣。

注意:此解決方案包含一些 ES6 特性,例如解構、箭頭函數等。

也許

_.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,展示了它是如何工作的。

讓數組的索引與uid相同怎么樣?,例如:

arr = [];
arr[1] = {uid: 1, name: "bla", description: "cucu"};
arr[2] = {uid: 2, name: "smth else", description: "cucarecu"};

這樣你就可以簡單地使用

arr[affectedId] = changedObject;

如果您不介意最終項目的順序,那么更簡潔的功能 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}];

如果項目存在,它將被排除,然后在最后添加新項目,基本上是替換,如果沒有找到項目,將在最后添加新對象。

通過這種方式,您將擁有不可變的列表。 唯一需要知道的是,例如,如果您要在屏幕上渲染列表,則需要進行某種排序以保持列表順序。

希望這對某人有用。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM