如何分组和依靠嵌套属性?如果这看起来像一个非常基本的问题,我很抱歉,但老实说我甚至不知道从哪里开始.
编辑我最初对上面的描述太模糊了,这可能是因为我的英语不是很好.我会在这里进一步详细说明.
如何按每个产品名称分组,然后汇总/计算唯一嵌套项目的数量?
我的数据来源:
[ { 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 } } ]
Scott Christ.. 12
我们可以使用Ramda来解决一个解决方案.
var data = [ { 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'} } ];
我们首先创建一个按名称对产品列表进行分组的功能.
const groupByProductName = R.groupBy(R.prop('product_name')); groupByProductName(data); // {"Another Cool Gadget": [{"product_name": "Another Cool Gadget"}, {"offer_code": {"name": "50OFF"}, "product_name": "Another Cool Gadget"}, {"offer_code": {"name": "50OFF"}, "product_name": "Another 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": "Cool Gadget"}]}
为了帮助计算不同商品代码的数量,我们将创建一个新功能,按商品代码名称(如果存在)进行分组,默认为_default
不存在.
我们可以使用此函数来映射生成的对象中的值groupByProductName
.
const groupByOfferCode = R.groupBy(R.pathOr('_default', ['offer_code', 'name'])); R.map(groupByOfferCode, groupByProductName(data)); // {"Another Cool Gadget": {"50OFF": [{"offer_code": {"name": "50OFF"}, "product_name": "Another Cool Gadget"}, {"offer_code": {"name": "50OFF"}, "product_name": "Another Cool Gadget"}], "_default": [{"product_name": "Another Cool Gadget"}]}, "Cool Gadget": {"50OFF": [{"offer_code": {"name": "50OFF"}, "product_name": "Cool Gadget"}, {"offer_code": {"name": "50OFF"}, "product_name": "Cool Gadget"}], "75OFF": [{"offer_code": {"name": "75OFF"}, "product_name": "Cool Gadget"}]}}
一旦我们有按名称分组的商品代码,我们将创建一个新函数来交换代码数组,只需每个数组的长度.
const countOfferCodes = R.map(R.length); R.map(countOfferCodes, R.map(groupByOfferCode, groupByProductName(data))); // {"Another Cool Gadget": {"50OFF": 2, "_default": 1}, "Cool Gadget": {"50OFF": 2, "75OFF": 1}}
一旦我们定义了这些函数,我们就可以获得接近您想要的输出的东西.
const process = products => R.map(countOfferCodes, R.map(groupByOfferCode, groupByProductName(products))); process(data); // {"Another 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')) ); process(data); // [{"count": {"50OFF": 2, "_default": 1}, "product_name": "Another Cool Gadget"}, {"count": {"50OFF": 2, "75OFF": 1}, "product_name": "Cool Gadget"}]
我们已经完成了.
我们可以使用Ramda来解决一个解决方案.
var data = [ { 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'} } ];
我们首先创建一个按名称对产品列表进行分组的功能.
const groupByProductName = R.groupBy(R.prop('product_name')); groupByProductName(data); // {"Another Cool Gadget": [{"product_name": "Another Cool Gadget"}, {"offer_code": {"name": "50OFF"}, "product_name": "Another Cool Gadget"}, {"offer_code": {"name": "50OFF"}, "product_name": "Another 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": "Cool Gadget"}]}
为了帮助计算不同商品代码的数量,我们将创建一个新功能,按商品代码名称(如果存在)进行分组,默认为_default
不存在.
我们可以使用此函数来映射生成的对象中的值groupByProductName
.
const groupByOfferCode = R.groupBy(R.pathOr('_default', ['offer_code', 'name'])); R.map(groupByOfferCode, groupByProductName(data)); // {"Another Cool Gadget": {"50OFF": [{"offer_code": {"name": "50OFF"}, "product_name": "Another Cool Gadget"}, {"offer_code": {"name": "50OFF"}, "product_name": "Another Cool Gadget"}], "_default": [{"product_name": "Another Cool Gadget"}]}, "Cool Gadget": {"50OFF": [{"offer_code": {"name": "50OFF"}, "product_name": "Cool Gadget"}, {"offer_code": {"name": "50OFF"}, "product_name": "Cool Gadget"}], "75OFF": [{"offer_code": {"name": "75OFF"}, "product_name": "Cool Gadget"}]}}
一旦我们有按名称分组的商品代码,我们将创建一个新函数来交换代码数组,只需每个数组的长度.
const countOfferCodes = R.map(R.length); R.map(countOfferCodes, R.map(groupByOfferCode, groupByProductName(data))); // {"Another Cool Gadget": {"50OFF": 2, "_default": 1}, "Cool Gadget": {"50OFF": 2, "75OFF": 1}}
一旦我们定义了这些函数,我们就可以获得接近您想要的输出的东西.
const process = products => R.map(countOfferCodes, R.map(groupByOfferCode, groupByProductName(products))); process(data); // {"Another 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')) ); process(data); // [{"count": {"50OFF": 2, "_default": 1}, "product_name": "Another Cool Gadget"}, {"count": {"50OFF": 2, "75OFF": 1}, "product_name": "Cool Gadget"}]
我们已经完成了.