如何对嵌套属性进行分组和计数?抱歉,这似乎是一个非常基本的问题,但老实说,我什至不知道从哪里开始。
编辑我最初对上面的描述不太清楚,这可能是因为我的英语不是很好。我将在这里尝试进一步阐述。
如何按每个产品名称分组,然后汇总/计算唯一嵌套商品的数量?
我的数据来源:
[
{
product_name: 'Cool Gadget',
offer_code: {name: '50off'}
},
{
product_name: 'Cool Gadget',
offer_code: {name: '50OFF'}
},
{
product_name: 'Cool Gadget',
offer_code: {name: '75OFF'}
},
{
product_name: 'Another Cool Gadget'
},
{
product_name: 'Another Cool Gadget',
offer_code: {name: '50OFF'}
},
{
product_name: 'Another Cool Gadget',
offer_code: {name: '50OFF'}
}
]
我的首选输出:
[
{
product_name: 'Cool Gadget',
count: {
'50OFF': 2,
'75OFF': 1
}
},
{
product_name: 'Another Cool Gadget',
count: {
'_default': 1,
'50OFF': 2
}
}
]
最佳答案
我们可以使用Ramda逐步介绍一种解决方案。
var数据= [
{
product_name:“酷小工具”,
offer_code:{名称:'50OFF'}
},
{
product_name:“酷小工具”,
offer_code:{名称:'50OFF'}
},
{
product_name:“酷小工具”,
offer_code:{名称:'75OFF'}
},
{
product_name:“另一个酷炫的小工具”
},
{
product_name:“另一个酷炫的小工具”,
offer_code:{名称:'50OFF'}
},
{
product_name:“另一个酷炫的小工具”,
offer_code:{名称:'50OFF'}
}
];
我们将从创建一个将产品列表按其名称分组的函数开始。
const groupByProductName = R.groupBy(R.prop('product_name'));
groupByProductName(data);
// {“另一个Cool Gadget”:[{“ product_name”:“另一个Cool Gadget”},{“ offer_code”:{“名称”:“ 50OFF”},“ product_name”:“另一个Cool Gadget”},{“ offer_code“:{” name“:” 50OFF“},” product_name“:”另一个Cool Gadget“}],” Cool Gadget“:[{” offer_code“:{” name“:” 50OFF“},” product_name“: “ Cool Gadget”},{“ offer_code”:{“ name”:“ 50OFF”},“ product_name”:“ Cool Gadget”},{“ offer_code”:{“ name”:“ 75OFF”},“ product_name”: “酷小工具”}]}
为了帮助计算不同的商品代码的数量,我们将创建一个新函数,以按商品代码名称(如果存在)分组,如果不存在,则默认为_default
。
我们可以使用此函数映射groupByProductName
生成的对象中的值。
const groupByOfferCode = R.groupBy(R.pathOr('_ default',['offer_code','name'])));
R.map(groupByOfferCode,groupByProductName(data));
// {“另一个Cool Gadget”:{“ 50OFF”:[{“ offer_code”:{“ name”:“ 50OFF”},“ product_name”:“另一个Cool Gadget”},{“ offer_code”:{“ name” :“” 50OFF“},” product_name“:”另一个Cool Gadget“}],” _default“:[{” product_name“:”另一个Cool Gadget“}]},” Cool Gadget“:{” 50OFF“:[{” offer_code“:{”名称“:” 50OFF“},” product_name“:”凉爽小工具“},{” offer_code“:{”名称“:” 50OFF“},” product_name“:”凉爽小工具“}],” 75OFF“:[{” offer_code“:{” name“:” 75OFF“},” product_name“:” Cool Gadget“}]}}
将商品代码按名称分组后,我们将创建一个新函数,以仅以每个数组的长度换出代码数组。
const countOfferCodes = R.map(R.length);
R.map(countOfferCodes,R.map(groupByOfferCode,groupByProductName(data)));
// {“另一个Cool Gadget”:{“ 50OFF”:2,“ _ default”:1},“ Cool Gadget”:{“ 50OFF”:2,“ 75OFF”:1}}
定义好这些功能后,我们可以获得与您期望的输出接近的东西。
const process = products => R.map(countOfferCodes,R.map(groupByOfferCode,groupByProductName(products)));
处理数据);
// {“另一个Cool Gadget”:{“ 50OFF”:2,“ _ default”:1},“ Cool Gadget”:{“ 50OFF”:2,“ 75OFF”:1}}
鉴于所有这些函数都将其输出直接馈入下一个函数的输入,因此可以使用R.pipe
进行声明,以创建转换管道。
const process = R.pipe(
groupByProductName,
R.map(groupByOfferCode),
R.map(countOfferCodes)
);
您可能已经注意到,管道中有两个彼此相邻的R.map
函数。由于说R.pipe(R.map(f), R.map(g))
必须与R.map(R.pipe(f, g))
相同的法律,我们可以通过将管道修改为以下内容来防止两次遍历列表。
const process = R.pipe(
groupByProductName,
R.map(R.pipe(
groupByOfferCode,
countOfferCodes
))
);
现在,要使输出达到所需的形状,我们可以创建一个函数,将对象转换为列表,然后将其添加到管道的末尾。
const objToList = R.pipe(
R.toPairs,
R.map(R.zipObj(['product_name','count']))
);
最后,我们可以在管道中添加一个函数,以按产品名称排序。所以一起:
const groupByProductName = R.groupBy(R.prop('product_name'));
const groupByOfferCode = R.groupBy(R.pathOr('_ default',['offer_code','name'])));
const countOfferCodes = R.map(R.length);
const objToList = R.pipe(
R.toPairs,
R.map(R.zipObj(['product_name','count']))
);
const process = R.pipe(
groupByProductName,
R.map(R.pipe(
groupByOfferCode,
countOfferCodes
)),
objToList,
R.sortBy(R.prop('product_name'))
);
处理数据);
// [{“ count”:{“ 50OFF”:2,“ _default”:1},“ product_name”:“另一个Cool Gadget”},{“ count”:{“ 50OFF”:2,“ 75OFF”:1 },“ product_name”:“酷小工具”}]
我们完成了。