很抱歉,标题不太清楚。我在下面做了一个简短的可复制示例,以说明我要尝试做的事情:
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
是包含人员对象的数组。每个人对象都有几个统计信息(在此示例中,这就是它们),并且每个统计信息都是具有makes, attempts, steals
或value, rank
三重奏的对象。
我想对每个人的统计对象的构成,尝试和值进行求和,并为汇总后的数据计算新的pct
值。
尽管我不确定这是否是解决问题的最佳方法,但我将很快发布使用ES6 reduce进行的尝试。任何帮助都将不胜感激!
答案 0 :(得分:3)
这将帮助您开始根据类型考虑数据。
Person
是具有四个属性的对象,
this
是Stat
对象(我们将在稍后定义)that
,这是另一个Stat
对象thos
是Rank
对象(我们也会定义)them
,这是另一个Rank
对象要继续,我们将Stat
指定为具有三个属性的对象,
makes
这是一个数字attempts
这是另一个数字pct
这是另一个数字最后,Rank
是一个具有两个属性的对象,
value
这是一个数字rank
这是另一个数字我们现在可以将arrayOfPeopleStats
视为一组项目,其中每个项目都是 Person 类型。为了组合相似的类型,我们定义了一种方法来create
我们类型的值和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
类型相似。您说{em>“没关系” 是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
,them
重命名为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
手动写数据相比,使用{ ... }
函数的另一个优点是构造函数可以为您提供帮助。请注意如何自动为pct
计算Stat
。这样可以防止某人编写无效的统计信息,例如{ makes: 1, attempts: 2, pct: 3 }
,其中pct
属性不等于makes/attempts
。如果不检查此数据的接收者,则无法确保pct
属性的完整性。另一方面,使用我们的构造函数,Stat.create
仅接受makes
和attempts
,并且pct
字段是自动计算的,从而保证了正确的pct
值。>
构造函数还可以阻止某人创建会导致错误的统计信息,例如Stat .create (10, 0)
,它将试图为10/0
计算pct
(除以零错误)财产-
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 =
{ create: (makes, attempts) =>
({ makes, attempts, pct: makes / attempts })
, concat: (s1, s2) =>
Stat .create
( s1.makes + s2.makes
, s1.attempts + s2.attempts
)
}
const Rank =
{ create: (value, rank) =>
({ value, rank })
, concat: (r1, r2) =>
Rank .create
( r1.value + r2.value
, Math .max (r1.rank, r2.rank)
)
}
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)
)
}
var data =
[ 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)
)
]
console .log (data .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 }
// }
但是如果data
是一个空数组怎么办?
[] .reduce (Person.concat)
// Uncaught TypeError: Reduce of empty array with no initial value
如果我们的代码片段可以在某些数组上工作,但在其他数组上坏了,那就不好了。数组用于表示 zero 或更多值,因此我们希望涵盖所有基础,包括零统计的情况。为所有个输入可能值定义的函数是total function,我们力求以这种方式编写程序。
错误消息提供了解决办法;我们必须提供初始值。例如-
中的0
const add = (x, y) =>
x + y
console .log
( [] .reduce (add, 0) // 0
, [ 1, 2, 3 ] .reduce (add, 0) // 6
)
使用初始值,即使数组为空,我们也始终会收到正确的结果。对于加号,我们使用初始值零,因为它是identity element。您可以将其视为一种空值。
如果我们尝试reduce
一组Person类型,那么Person的初始值是什么?
arrayOfPeopleStat .reduce (Person.concat, ???)
如果可能,我们为每种类型定义一个 empty 值。我们将从Stat
-
const Stat =
{ empty:
{ makes: 0
, attempts: 0
, pct: 0
}
, create: ...
, concat: ...
}
接下来,我们将做Rank
-
const Rank =
{ empty:
{ value: 0
, rank: 0
}
, create: ...
, concat: ...
}
同样,我们将Person视为复合数据,即由其他数据构成的数据。我们依靠Stat.empty
和Rank.empty
来创建Person.empty
-
const Person =
{ empty:
{ a: Stat.empty
, b: Stat.empty
, c: Rank.empty
, d: Rank.empty
}
, create: ...
, concat: ...
}
现在我们可以将Person.empty
指定为初始值,并防止出现加重错误-
arrayOfPeopleStat .reduce (Person.concat, Person.empty)
// { 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 }
// }
[] .reduce (Person.concat, Person.empty)
// { a: { makes: 0, attempts: 0, pct: 0 }
// , b: { makes: 0, attempts: 0, pct: 0 }
// , c: { value: 0, rank: 0 }
// , d: { value: 0, rank: 0 }
// }
作为奖励,您现在对monoids有了基本的了解。
答案 1 :(得分:1)
在map
和reduce
之间进行选择时,您可以认为map
将返回一个新的array
,其长度与原始长度相同。它不是您想要的,所以您绝对不能使用它。您实际上想将数组简化为一个对象。因此,只需使用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,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}}];
const resp = Object.values(arrayOfPeopleStats).reduce((obj, { this: localThis, that, thos, them }) => {
obj.this = { makes: obj.this.makes + localThis.makes, attempts: obj.this.attempts + localThis.attempts };
obj.this.pct = obj.this.makes / obj.this.attempts;
obj.that = { makes: obj.that.makes + that.makes, attempts: obj.that.attempts + that.attempts };
obj.that.pct = obj.that.makes / obj.that.attempts;
obj.thos = { value: obj.thos.value + thos.value, rank: obj.thos.rank + thos.rank };
obj.them = { value: obj.them.value + them.value, rank: obj.thos.rank + them.rank };
return obj;
})
const formattedResp = [{ allPeople: resp }]
console.log(formattedResp)
我不建议您使用this
作为属性名称,因为它可能与this
关键字冲突。
答案 2 :(得分:-1)
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的说明,请参见https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce。