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

编辑我最初对上面的描述不太清楚,这可能是因为我的英语不是很好。我将在这里尝试进一步阐述。

如何按每个产品名称分组,然后汇总/计算唯一嵌套商品的数量?

我的数据来源:

[
  {
    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”:“酷小工具”}]


我们完成了。

09-25 20:02