Javascript 使用ES6 reduce或map计算数组嵌套对象中的总和和百分比
如果标题不是特别清楚,请道歉。我在下面做了一个简短的可复制的例子,说明我正在尝试做的事情:Javascript 使用ES6 reduce或map计算数组嵌套对象中的总和和百分比,javascript,ecmascript-6,reduce,Javascript,Ecmascript 6,Reduce,如果标题不是特别清楚,请道歉。我在下面做了一个简短的可复制的例子,说明我正在尝试做的事情: var arrayOfPeopleStats = [ person1 = { this: { makes: 10, attempts: 15, pct: .666667 }, that: { makes: 12, attempts: 16, pct: .75 }, thos: { value: 10, rank: 24 }, them: { value: 15, ra
var arrayOfPeopleStats = [
person1 = {
this: { makes: 10, attempts: 15, pct: .666667 },
that: { makes: 12, attempts: 16, pct: .75 },
thos: { value: 10, rank: 24 },
them: { value: 15, rank: 11 }
},
person2 = {
this: { makes: 5, attempts: 15, pct: .333333 },
that: { makes: 10, attempts: 12, pct: .83333 },
thos: { value: 4, rank: 40 },
them: { value: 3, rank: 32 }
},
person3 = {
this: { makes: 14, attempts: 14, pct: 1 },
that: { makes: 7, attempts: 8, pct: .875 },
thos: { value: 12, rank: 12 },
them: { value: 13, rank: 10 }
}
]
var desiredOutput = [
allPeople: {
this: { makes: 29, attempts: 44, pct: .65909 },
that: { makes: 29, attempts: 36, pct: .80555 },
thos: { value: 26, rank: doesnt matter },
them: { value: 31, rank: doesnt matter }
}
]
arrayOfPeopleStats
是一个包含person对象的数组。每个person对象都有一对统计信息(本例中为this、that、this),每个统计信息都是一个对象,具有三个属性:make、attempts、steals或value、rank
我想对每个人在stat对象上的make、尝试和值进行求和,并为求和的数据计算新的pct
值
我将很快发布我使用ES6 reduce所做的尝试,尽管我不确定这是解决这个问题的最佳方法。非常感谢您在这方面的任何帮助
arrayOfPeopleStats.reduce((a, v) => {
a.allPeople.this = {
makes: a.allPeople.this.makes + v.this,
attempts: a.allPeople.this.attempts + v.this.attempts,
};
a.allPeople.that = {
makes: a.allPeople.that.makes + v.that.makes,
attempts: a.allPeople.that.attempts + v.that.attempts,
};
a.allPeople.thos = {
value: a.allPeople.thos.value + v.thos.value,
};
a.allPeople.them = {
value: a.allPeople.them.value + v.them.value,
};
a.allPeople.this.pct = a.allPeople.this.makes / a.allPeople.this.attempts
a.allPeople.that.pct = a.allPeople.that.makes / a.allPeople.that.attempts
return a;
}, {allPeople: {
this: { makes: 0, attempts: 0, pct: 0 },
that: { makes: 0, attempts: 0, pct: 0 },
thos: { value: 0, rank: 0 },
them: { value: 0, rank: 0 }
}
}});
我忽略了排名,正如你所说的,这无关紧要,上面的解决方案总是0。我还选择了不将结果对象包装在数组中,正如您在所需结果中所做的那样。有关此API的解释,请参阅。它将帮助您开始从类型的角度考虑数据
Person
是一个具有四个属性的对象
this
是一个Stat
对象(我们将很快定义)那是另一个Stat
对象
thos
这是一个Rank
对象(我们也将定义它)它们
是另一个等级
对象Stat
指定为具有三个属性的对象
生成
哪个是数字尝试
哪个是另一个数字pct
哪个是另一个数字Rank
是一个具有两个属性的对象
值
哪个是数字rank
哪个是另一个数字arrayOfPeopleStats
视为一个项目数组,其中每个项目都是Person类型的。为了组合相似的类型,我们定义了一种方法来创建我们类型的值,以及一种方法来concat
(添加)它们
我将首先定义较小的类型,Stat
-
const Stat =
{ create: (makes, attempts) =>
({ makes, attempts, pct: makes / attempts })
, concat: (s1, s2) =>
Stat .create
( s1.makes + s2.makes
, s1.attempts + s2.attempts
)
}
等级
类型类似。您说过,rank
的组合值是多少“无关紧要”,但这表明您必须做出选择。您可以选择一个或另一个,将两个值相加,或完全使用其他选项。在这个实现中,我们选择最高的rank
值-
const Rank =
{ create: (value, rank) =>
({ value, rank })
, concat: (r1, r2) =>
Rank .create
( r1.value + r2.value
, Math .max (r1.rank, r2.rank)
)
}
最后,我们实现了Person
。我将this
,that
,thos
,this
重命名为a
,b
,c
,d
,因为this
是JavaScript中的一个特殊变量,我认为它使示例更容易理解;无论如何,你问题中的数据看起来都是假的。这里需要注意的是,Person.concat
函数依赖于Stat.concat
和Rank.concat
,将每种类型的组合逻辑很好地分开-
const Person =
{ create: (a, b, c, d) =>
({ a, b, c, d })
, concat: (p1, p2) =>
Person .create
( Stat .concat (p1.a, p2.a)
, Stat .concat (p1.b, p2.b)
, Rank .concat (p1.c, p2.c)
, Rank .concat (p1.d, p2.d)
)
}
现在,要组合数组中的所有person
项,只需使用person.concat
操作进行缩减即可-
arrayOfPeopleStat .reduce (Person.concat)
// { a: { makes: 29, attempts: 44, pct: 0.6590909090909091 }
// , b: { makes: 29, attempts: 36, pct: 0.8055555555555556 }
// , c: { value: 26, rank: 40 }
// , d: { value: 31, rank: 32 }
// }
请注意,当您已经很好地定义了数据构造函数时,使用{…}
手工写出数据既麻烦又容易出错。而是使用您类型的create
功能-
var arrayOfPeopleStat =
[ Person .create
( Stat .create (10, 15)
, Stat .create (12, 16)
, Rank .create (10, 24)
, Rank .create (15, 11)
)
, Person .create
( Stat .create (5, 15)
, Stat .create (10, 12)
, Rank .create (4, 40)
, Rank .create (3, 32)
)
, Person .create
( Stat .create (14, 14)
, Stat .create (7, 8)
, Rank .create (12, 12)
, Rank .create (13, 10)
)
]
与使用{…}
手工写出数据相比,使用create
函数的另一个优点是构造函数可以为您提供帮助。注意如何为Stat
自动计算pct
。这可以防止有人编写无效的统计数据,如pct
属性不等于makes/attempts
的{makes:1,attempts:2,pct:3}
。如果此数据的接收者未进行检查,我们无法确保pct
属性的完整性。另一方面,使用我们的构造函数,Stat.create
只接受makes
和尝试
,并自动计算pct
字段,确保正确的pct
值
构造函数还可以防止有人创建会导致错误的stat,例如stat.create(10,0)
,它将尝试为pct
属性计算10/0
(除以零错误)-
const Stat =
{ create: (makes = 0, attempts = 0) =>
attempts === 0
? { makes, attempts, pct: 0 } // instead of throwing error
: { makes, attempts, pct: makes / attempts } // safe to divide
, concat: ...
}
最终这些选择取决于你。在这种情况下,另一个程序员可能会赞成错误。比如-
Stat .create (10, 0)
// Error: invalid Stat. makes (10) cannot be greater than attempts (0). attempts cannot be zero.
当然,reduce
的结果是相同的-
arrayOfPeopleStat .reduce (Person.concat)
// { a: { makes: 29, attempts: 44, pct: 0.6590909090909091 }
// , b: { makes: 29, attempts: 36, pct: 0.8055555555555556 }
// , c: { value: 26, rank: 40 }
// , d: { value: 31, rank: 32 }
// }
展开下面的代码段,在您自己的浏览器中验证结果-
const Stat=
{创建:(创建、尝试)=>
({makes,attempts,pct:makes/attempts})
,concat:(s1,s2)=>
统计,创建
(s1.makes+s2.makes)
,s1.尝试次数+s2.尝试次数
)
}
常数秩=
{创建:(值、等级)=>
({值,秩})
,concat:(r1,r2)=>
排名。创建
(r1.value+r2.value)
,Math.max(r1.rank,r2.rank)
)
}
警察=
{创建:(a、b、c、d)=>
({a,b,c,d})
,concat:(p1,p2)=>
人。创造
(统计浓度(p1.a、p2.a)
,统计浓度(p1.b,p2.b)
,秩.concat(p1.c,p2.c)
,职级:concat(p1.d,p2.d)
)
}
var数据=
[个人,创建
(统计创建(10,15)
,Stat.create(12,16)
,排名。创建(10,24)
,排名。创建(15,11)
)
,Person.create
(统计创建(5,15)
,Stat.create(10,12)
,排名。创建(4,40)
,排名。创建(3,32)
)
,Person.create
(统计创建(14,14)
,统计创建(7,8)
,排名。创建(12,12)
,排名。创建(13,10)
)
]
console.log(data.reduce(Person.concat)