Javascript - 计算对象数组中的重复项并将计数存储为新对象
Posted
技术标签:
【中文标题】Javascript - 计算对象数组中的重复项并将计数存储为新对象【英文标题】:Javascript - Counting duplicates in object array and storing the count as a new object 【发布时间】:2017-12-28 17:44:54 【问题描述】:我有一组作为产品的 javascript 对象。这些产品以购物车的形式显示在列表中。
我想根据_.id
值计算数组中重复产品的数量,并从数组中删除这些对象,并用更新的版本和一个名为count
的新键替换它们,其值为总计此对象出现的次数。
到目前为止,我已经尝试了多种方法,并且在 google 上进行了搜索,但没有发现可以正确完成这项工作。
我将使用的数组类型示例如下:
[
_id: "5971df93bfef201237985c4d",
slug: "5971df93bfef201237985c4d",
taxPercentage: 23,
totalCost: 9.99,
currency: "EUR",
,
]
所以我希望我的最终结果是这样的 - 它删除重复值并用相同的对象替换它,但添加一个名为 count 的新键,其值是对象最初的次数在数组中:
[
_id: "5971df93bfef201237985c4d",
slug: "5971df93bfef201237985c4d",
taxPercentage: 23,
totalCost: 9.99,
currency: "EUR",
count: 2, // whatever the count is
,
]
到目前为止,我都在使用这种方法:
var count = [];
if (cart.cart.products != undefined)
let namestUi =
renderNames(names)
return Array.from(
names.reduce( (counters, object) =>
counters.set(object._id, (counters.get(object._id) || 0) + 1),
new Map() ),
([object, count]) =>
var filterObj = names.filter(function(e)
return e._id == object;
);
return (filterObj, count)
);
;
count = namestUi.renderNames(cart.cart.products);
console.log(count)
但它返回如下值:
filterObj: Array // the array of the duplicates, count: 2
filterObj: Array, count: 1
并且由于我使用带有列表视图的 React-Native,因此这样的事情将无法正常工作。
它只需要以以前的方式(一个数组)存储项目,但有一个名为 count
的新子项。
欢迎任何帮助!
【问题讨论】:
您有一个对象数组,其中相同 id 的对象多次出现。现在您想创建一个数组,它将相同的对象组合成一个并添加一个计数属性(指示相同对象出现了多少次)。这是正确的吗?? 是的,差不多了 【参考方案1】:我会坚持reduce
,使用Map
并传播其values
以获得最终结果:
const names = [ _id: 1 , _id: 1, _id: 2, _id: 1];
const result = [...names.reduce( (mp, o) =>
if (!mp.has(o._id)) mp.set(o._id, ...o, count: 0 );
mp.get(o._id).count++;
return mp;
, new Map).values()];
console.log(result);
或者您可以先在映射中创建计数为零的所有键(使用 Map 构造函数),然后再次迭代数据以更新计数器。这种任务拆分使得代码比reduce
更简洁:
const names = [ _id: 1 , _id: 1, _id: 2, _id: 1];
const mp = new Map(names.map(o => [o._id, ...o, count: 0 ]));
for (const _id of names) mp.get(_id).count++;
const result = Array.from(mp.values());
console.log(result);
当您拥有多个密钥时,一个想法是加入JSON.stringify([ ])
:
const names = [cat: 1, sub: 1, cat: 1, sub: 2, cat: 2, sub: 1, cat: 1, sub: 1];
const result = [...names.reduce( (mp, o) =>
const key = JSON.stringify([o.cat, o.sub]);
if (!mp.has(key)) mp.set(key, ...o, count: 0 );
mp.get(key).count++;
return mp;
, new Map).values()];
console.log(result);
【讨论】:
这个结果也很好,更简洁更好的语法【参考方案2】:最简单的可能是地图:
var map=new Map();
names.forEach(function(el)
if(map.has(el["_id"]))
map.get(el["_id"]).count++;
else
map.set(el["_id"],Object.assign(el,count:1));
);
然后重新创建一个数组:
names=[...map.values()];
或者以旧的哈希/数组方式:
var hash=,result=[];
names.forEach(function(name)
var id=name["_id"];
if(hash[id])
hash[id].count++;
else
result.push(hash[id]=
count:1,
...name
);
);
console.log(result);
【讨论】:
使用Object.assign(el,count:1)
修改原始对象。您应该执行相反的操作:Object.assign(count:1, el)
,或者,处理并覆盖现有的 count
属性:Object.assign(, el, count:1)
@trincot 是的,提供了两种解决方案,我认为如果他关心性能或原始不变,我认为 OP 可以选择一个 mixin。【参考方案3】:
您可以使用array.reduce
方法将原始数组转换为具有所需结构的新数组。
我们可以只检查 id 是否存在于数组中,并相应地使用具有 count 属性的新对象更新数组。
let arr = [
id: 1
,
id: 1
,
id: 1
,
id: 2
,
id: 2
];
let new_arr = arr.reduce((ar, obj) =>
let bool = false;
if (!ar)
ar = [];
ar.forEach((a) =>
if (a.id === obj.id)
a.count++;
bool = true;
);
if (!bool)
obj.count = 1;
ar.push(obj);
return ar;
, []);
console.log(new_arr);
【讨论】:
以上是关于Javascript - 计算对象数组中的重复项并将计数存储为新对象的主要内容,如果未能解决你的问题,请参考以下文章
Javascript - 计算对象数组中的重复项并将计数存储为新对象