如何在对象数组中查找和更新值?
Posted
技术标签:
【中文标题】如何在对象数组中查找和更新值?【英文标题】:How can I find and update values in an array of objects? 【发布时间】:2016-05-14 08:47:25 【问题描述】:我有一个对象数组。我想通过某个字段找到,然后更改它:
var item = ...
var items = [id:2, id:2, id:2];
var foundItem = items.find(x => x.id == item.id);
foundItem = item;
我希望它改变原始对象。如何? (我不在乎它是否也会出现在 Lodash 中。)
【问题讨论】:
让你的新对象item
包含id
键?或者您介意在数组条目中包含来自 item
对象的 id 以及所有属性?
【参考方案1】:
您可以使用findIndex在对象的数组中查找索引并根据需要进行替换:
var item = ...
var items = [id:2, id:2, id:2];
var foundIndex = items.findIndex(x => x.id == item.id);
items[foundIndex] = item;
这假定了唯一的 ID。如果您的 ID 重复(如您的示例中所示),则使用 forEach 可能会更好:
items.forEach((element, index) =>
if(element.id === item.id)
items[index] = item;
);
【讨论】:
@georg 不过这会返回一个新数组。 => 函数在 IE11 中不起作用。最近被这个咬了。 使用let
关键字而不是var
可能会更好
仅供参考,这在某些版本的 phantomJS 中不起作用
我更喜欢@CodingIntrigue 使用的更详细的方法,而不是@georg 使用的单行map
。弄清楚发生了什么所需的心理体操更少。值得额外的代码行。【参考方案2】:
我最好的方法是:
var item = ...
var items = [id:2, id:2, id:2];
items[items.findIndex(el => el.id === item.id)] = item;
参考findIndex
如果你不想用新对象替换,而是复制item
的字段,你可以使用Object.assign
:
Object.assign(items[items.findIndex(el => el.id === item.id)], item)
作为.map()
的替代方案:
Object.assign(items, items.map(el => el.id === item.id? item : el))
Functional approach:
不要修改数组,使用一个新的,这样就不会产生副作用
const updatedItems = items.map(el => el.id === item.id ? item : el)
注意
如果使用得当,对对象的引用不会丢失,因此您甚至可以使用原始对象引用,而不是创建新的引用。
const myArr = [ id: 1 , id: 2 , id: 9 ];
const [a, b, c] = myArr;
// modify original reference will change object in the array
a.color = 'green';
console.log(myArr[0].color); // outputs 'green'
这个问题通常发生在使用数据库中的列表,然后映射列表以生成 html 内容,该内容将修改列表的元素,然后我们需要更新列表并将其作为列表发送回数据库。
好消息是,保留了引用,因此您可以组织代码以利用它,并将list
视为具有免费标识的对象,这些标识是从 0 到 length -1
的整数。因此,每次访问对象的任何属性时,都以list[i]
进行操作,并且不会丢失引用,并且原始对象会更改。请记住,当您的事实来源只有一个(创建的对象)并且您的应用程序始终始终使用相同的对象(而不是从数据库中获取多次并将其分配给list
)时,这很有用组件)。
坏消息是架构是错误的,如果这是你需要的,你应该通过 ids(字典)接收一个对象,比如
1232: id: 1232, ...,
asdf234asf: id: 'asdf234asf', ...,
...
这样,您就不会在数组中搜索,这会消耗资源。您“只需在对象中通过键访问”,这是即时且高效的。
【讨论】:
如果原始问题是英文的,请链接到英文页面。此外,此示例假定始终找到对象。 您可以随时将其包装在 try catch 表达式中...对吗? 对于帖子的问题完全是字面意思,他想编辑数组中的一个元素。他不想知道它是否存在,所以我们假设他之前已经这样做了。 @SoldeplataSaketos 是的,您可以将其包装在try/catch
中,但您不应该这样做,因为找不到该元素并不是例外情况;这是一个标准情况,您应该检查findIndex
的返回值,然后仅在找到元素时更新数组。【参考方案3】:
另一种方法是使用splice。
splice()
方法通过删除或替换现有元素和/或添加新元素 in place 来更改数组的内容。
注意:如果您正在使用响应式框架,它将更新“视图”,您的数组“知道”您已更新它。
答案:
var item = ...
var items = [id:2, id:2, id:2];
let foundIndex = items.findIndex(element => element.id === item.id)
items.splice(foundIndex, 1, item)
如果你只想改变一个项目的值,你可以使用find函数:
// Retrieve item and assign ref to updatedItem
let updatedItem = items.find((element) => return element.id === item.id )
// Modify object property
updatedItem.aProp = ds.aProp
【讨论】:
【参考方案4】:可以使用Filter。
const list = [id:0, id:1, id:2];
let listCopy = [...list];
let filteredDataSource = listCopy.filter((item) =>
if (item.id === 1)
item.id = 12345;
return item;
);
console.log(filteredDataSource);
数组[对象id:0,对象id:12345,对象id:2]
【讨论】:
我喜欢过滤器,因为它允许创建一个新数组,因此不存在的条目也被“删除”【参考方案5】:给定一个改变的对象和一个数组:
const item = ...
let items = [id:2, id:3, id:4];
通过迭代数组来用新对象更新数组:
items = items.map(x => (x.id === item.id) ? item : x)
【讨论】:
我认为这是最好的解决方案,因为它具有最好的性能,因为它只遍历数组一次并且还更改了数组的引用,因此它可以避免可变情况 @Spencer 因此映射循环遍历items
数组中的每个项目,并检查该项目的id
是否与const
变量中项目的id
相同。如果找到一个,则将 x
映射到 item
,这是 const
变量中的那个,否则它在 items
数组中保留相同的元素 x
。【参考方案6】:
虽然大多数现有答案都很棒,但我想包括一个使用传统 for 循环的答案,在这里也应该考虑。 OP 请求一个与 ES5/ES6 兼容的答案,并且适用传统的 for 循环:)
在这种情况下使用数组函数的问题在于它们不会改变对象,但在这种情况下,改变是必需的。使用传统 for 循环的性能提升只是一个(巨大的)奖励。
const findThis = 2;
const items = [id:1, ..., id:2, ..., id:3, ...];
for (let i = 0, l = items.length; i < l; ++i)
if (items[i].id === findThis)
items[i].iAmChanged = true;
break;
虽然我非常喜欢数组函数,但不要让它们成为您工具箱中的唯一工具。如果目的是改变数组,那么它们不是最合适的。
【讨论】:
【参考方案7】:为我工作
let returnPayments = [ ...this.payments ];
returnPayments[this.payments.findIndex(x => x.id == this.payment.id)] = this.payment;
【讨论】:
请不要只是粘贴代码。说明正在做什么以及如何解决问题。 接受最多的答案并没有太大的不同,但您并没有指出他们更新那里的答案..这是为什么?【参考方案8】:使用扩展运算符的单线。
const updatedData = originalData.map(x => (x.id === id ? ...x, updatedField: 1 : x));
【讨论】:
正是我想要的! “问题”是如果我们说 id 是以随机方式创建的,你最终会得到具有相同 id 的对象【参考方案9】:你也可以这样做
var item = ...
var items = [id:2, id:2, id:2];
var foundItem = items.filter((x) => x.id == item.id).pop();
foundItem = item;
或
items.filter((x) => x.id == item.id).pop()=item;
【讨论】:
以上是关于如何在对象数组中查找和更新值?的主要内容,如果未能解决你的问题,请参考以下文章