Javascript 总结对象数组的频率
假设我有以下对象数组Javascript 总结对象数组的频率,javascript,arrays,object,ecmascript-6,counting,Javascript,Arrays,Object,Ecmascript 6,Counting,假设我有以下对象数组 data = [ { x: 1, y: 1 }, { x: 2, y: 2 }, { x: 3, y: 3 }, { x: 2, y: 2 }, { x: 1, y: 1 }, { x: 1, y: 2 }, { x: 1, y: 1 } ] 我需要的是总结数组中相同对象的频率。输出将如下所示: summary = [ { x: 1, y: 1, f: 3 }, { x: 1, y: 2, f: 1 }, { x: 2, y: 2,
data = [
{ x: 1, y: 1 },
{ x: 2, y: 2 },
{ x: 3, y: 3 },
{ x: 2, y: 2 },
{ x: 1, y: 1 },
{ x: 1, y: 2 },
{ x: 1, y: 1 }
]
我需要的是总结数组中相同对象的频率。输出将如下所示:
summary = [
{ x: 1, y: 1, f: 3 },
{ x: 1, y: 2, f: 1 },
{ x: 2, y: 2, f: 2 },
{ x: 3, y: 3, f: 1 }
]
现在我有了这个代码
const summary = data.map((item, index, array) => {
return { x: item.x, y: item.y, f: array.filter(i => i === item).length };
});
但是我想我可以通过使用
reduce
或includes
做得更好。有什么想法吗?简化为一个对象,其关键帧唯一地表示一个对象,其值就是对象(具有x
、y
和f
属性)。在每次迭代中,增加相应键的f
属性,或者在累加器上创建该键(如果该键尚不存在):
const数据=[
{x:1,y:1},
{x:2,y:2},
{x:3,y:3},
{x:2,y:2},
{x:1,y:1},
{x:1,y:2},
{x:1,y:1}
];
const countObj=数据减少((a,obj)=>{
常量objString=obj.x+'.'+obj.y;
如果(!a[objString]){
a[objString]={…obj,f:1};
}否则{
a[objString].f++;
}
返回a;
}, {});
常量输出=对象值(countObj);
控制台日志(输出)代码>不要使用map
-最好使用reduce
这样:
const summary = Object.values(data.reduce((a, { x, y }) => {
a[`${x}-${y}`] = a[`${x}-${y}`] || { x, y, f: 0 };
a[`${x}-${y}`].f++;
return a;
}, {}));
基于的简单解决方案如下所示:
const数据=[
{x:1,y:1},
{x:2,y:2},
{x:3,y:3},
{x:2,y:2},
{x:1,y:1},
{x:1,y:2},
{x:1,y:1}
];
const summary=data.reduce((频率摘要,项)=>{
/*在当前频率摘要列表中查找当前项的匹配项*/
const itemMatch=frequencysummmary.find(i=>i.x==item.x&&i.y==item.y)
如果(!itemMatch){
/*如果未找到匹配项,则在结果中添加初始频率为1的新项*/
推送({…项,f:1});
}
否则{
/*如果找到匹配项,则增加该匹配项的频率计数*/
itemMatch.f++;
}
返回频率汇总;
}, []);
log(summary)
我知道使用reduce可能更好,但我倾向于使用forEach和findIndex以提高可读性
var data = [
{ x: 1, y: 1 },
{ x: 2, y: 2 },
{ x: 3, y: 3 },
{ x: 2, y: 2 },
{ x: 1, y: 1 },
{ x: 1, y: 2 },
{ x: 1, y: 1 }
];
var summary = [];
data.forEach(function(d){
var idx = summary.findIndex(function(i){
return i.x === d.x && i.y === d.y;
});
if(idx < 0){
var sum = Object.assign({}, d);
sum.f = 1;
summary.push(sum);
} else {
summary[idx].f = summary[idx].f + 1;
}
});
console.log(summary);
var数据=[
{x:1,y:1},
{x:2,y:2},
{x:3,y:3},
{x:2,y:2},
{x:1,y:1},
{x:1,y:2},
{x:1,y:1}
];
var汇总=[];
data.forEach(函数(d){
var idx=summary.findIndex(函数(i){
返回i.x==d.x&&i.y==d.y;
});
if(idx<0){
var sum=Object.assign({},d);
总和f=1;
推送(sum);
}否则{
摘要[idx].f=摘要[idx].f+1;
}
});
控制台日志(摘要);
创建嵌套对象。外部对象使用x
值作为键,嵌套对象包含y
值作为键,这些值是频率
数据=[
{x:1,y:1},
{x:2,y:2},
{x:3,y:3},
{x:2,y:2},
{x:1,y:1},
{x:1,y:2},
{x:1,y:1}
];
const nested=data.reduce((a,{x,y})=>{
a[x]=a[x]|{};
a[x][y]=a[x][y]?a[x][y]+1:1
返回a;
}, {});
const summary=[];
forEach(y=>summary.push({x,y,f:nested[x][y]}));
控制台日志(摘要)
您可以使用减少
和映射
,使用x和y作为键,在每次迭代中检查相同的键是否已经出现在映射上,而不是仅仅增加f
计数1
,如果没有,则将其设置为1
const data=[{x:1,y:1},{x:2,y:2},{x:3,y:3},{x:2,y:2},{x:1,y:1},{x:1,y:2},{x:1,y:1}];
const countObj=数据减少((a,obj)=>{
常量objString=obj.x+'.'+obj.y;
让value=a.get(objString)| | obj
设f=value&&value.f | | 0
a、 集合(对象字符串,{…值,f:f+1})
返回a;
},新地图());
log([…countObj.values()])代码>
注:
此代码段将用于任意对象的数组,只要它们是可字符串化的
结果不排序,因为对象键不排序。如果这是一个问题,请随意排序
你要做的是计算一个对象在数组中存在的次数。您可能希望结果位于对象外部,而不是嵌入其中。沿着这些路线的东西可能更易于管理,返回对象描述到计数的映射:
您应该使用reduce
map
始终返回具有相同数量元素的数组,但您希望组合等效元素。i===item
不适用于对象。它要求对象是相同的,而不仅仅是具有相同的属性。请看@Barmar确实,我没有检查好这段代码是否工作正常。我知道我需要进一步删除映射后的重复项。无论如何,谢谢你的建议。对我来说,这似乎是最优雅、最普遍的方法,所以我给了你支票。但很高兴看到大家都发表了很多好的想法,谢谢:)
Object.values(data.reduce((sum, i) => {
i_str = JSON.stringify(i); // objects can't be keys
sum[i_str] = Object.assign({}, i, {f: sum[i_str] ? sum[i_str].f+1 : 1});
return sum;
}, {}));
data.reduce((sum, i) => {
i_str = JSON.stringify(i); // objects can't be keys
sum[i_str] = sum[i_str] ? sum[i_str]+1 : 1;
return sum;
}, {});