繁体   English   中英

使用Ramda / LoDash / Undercore在嵌套属性上唯一地分组和计数

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

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

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

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

我的数据来源:

[
  {
    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 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声明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))相同, 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"}]

我们完成了。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM