使用Ramda/LoDash/Undercore对嵌套属性进行唯一分组和计数

Group and Count Uniquely on Nested Properties with Ramda/LoDash/Underscore

本文关键字:唯一 属性 LoDash Ramda Undercore 使用 嵌套      更新时间:2023-09-26

如何对嵌套属性进行分组和计数?如果这看起来是一个非常基本的问题,我很抱歉,但老实说,我甚至不知道从哪里开始。

编辑我最初对上面的描述太模糊了,可能是因为我的英语不太好。我将在这里进一步阐述。

如何按每个产品名称进行分组,然后聚合/计数唯一嵌套项目的数量?

我的数据来源:

[
  {
    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:{name:"50OFF"}},{product_name:"酷小工具",offer_code:{name:"50OFF"}},{product_name:"酷小工具",offer_code:{name:"75OFF"}},{product_name:"另一个很酷的小工具"},{product_name:"另一个很酷的小工具",offer_code:{name:"50OFF"}},{product_name:"另一个很酷的小工具",offer_code:{name:"50OFF"}}];

我们将从创建一个函数开始,该函数将按产品名称对产品列表进行分组。

const groupByProductName=R.groupBy(R.prop('product_name'));groupByProductName(数据);//{"另一个很酷的小工具":[{"product_name":"Another Cool Gadget"},{"offer_code":{"name":"50OFF"},"酷的小工具":[{"offer_code":{"name":"50OFF"},"product_name":"酷的小配件"}

为了帮助计算不同优惠代码的数量,我们将创建一个新函数,根据优惠代码名称(如果存在)进行分组,如果不存在,则默认为_default

我们可以使用此函数映射groupByProductName生成的对象中的值。

const groupByOfferCode=R.groupBy(R.pathOr('_default',['offer_code','name']));R.map(groupByOfferCode,groupByProductName(数据));//{"另一个很酷的小工具":{"50OFF":[{"offer_code":{"name":"50FF"},"product_name":"Another Cool Gadget"},"酷小工具":{"50OFF":[{"offer_code":{"name":"50OFF"},"product_name":"酷小工具"}

一旦我们将优惠代码按名称分组,我们将创建一个新函数来交换代码数组,其中只有每个数组的长度。

const countOfferCodes=R.map(R.length);R.map(countOfferCodes,R.map(groupByOfferCode,groupByProductName(数据)));//{"另一个酷小工具":{"50OFF":2,"_default":1},"酷小工具";{

一旦我们定义了这些函数,我们就可以得到接近您想要的输出。

const process=products=>R.map(countOfferCodes,R.map(groupByOfferCode,groupByProductName(products));过程(数据);//{"另一个酷小工具":{"50OFF":2,"_default":1},"酷小工具";{

假设所有这些函数都将其输出直接提供给下一个函数的输入,则可以使用R.pipe来声明这一点,以创建转换管道。

const过程=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过程=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过程=R.pipe(groupByProductName,R.map(R.pipe(groupByOfferCode,countOfferCodes)),objToList,R.sortBy(R.prop('product_name')));过程(数据);//[{"count":{"50OFF":2,"_default":1},"product_name":"Another Cool Gadget"},{"count":{

我们完了。