简体   繁体   English

Ramda - 通过多个分组变换数组

[英]Ramda - Transform array by multiple groupings

I am trying to accomplish the following using ramda :我正在尝试使用ramda完成以下操作:

Here's a sample of what the array will look like:这是array的外观示例:

[
  {
    id: 1,
    value: "ON",
    type: "TYPE_1"
  },
  {
    id: 1,
    value: "OFF",
    type: "TYPE_1"
  },
  {
    id: 2,
    value: "ON",
    type: "TYPE_1"
  }, {
    id: 3,
    value: "OFF",
    type: "TYPE_2"
  },
  {
    id: 3,
    value: "OFF",
    type: "TYPE_2"
  },
  {
    id: 3,
    value: "OFF",
    type: "TYPE_2"
  }
]

Here's how I want it to look:这是我希望它的外观:

[
 {
  name: "TYPE_1"
  enabled: 2,
  disabled: 0,
 },
 {
  name: "TYPE_2",
  enabled: 0,
  disabled: 1
 }
]

Basically I need to group by type and id where their combination could be repeated but only account for one.基本上我需要按typeid分组,它们的组合可以重复但只占一个。

Here's what I've already attempted:这是我已经尝试过的:

pipe(
  groupBy(prop('type')),
  map(applySpec({
    name: pipe(head, prop('type')),
    enabled: reduce((acc, item) => item.value === "ON" ? add(acc, 1) : acc, 0),
    disabled: reduce((acc, item) => item.value === "OFF" ? add(acc, 1) : acc, 0) 
  })),
  values,
)(list) 

But it does not work as this returns the following:但它不起作用,因为它返回以下内容:

[
 {
  name: "TYPE_1",
  enabled: 2,
  disabled: 1
 },
 {
  type: "TYPE_2",
  enabled: 0,
  disabled: 3
]

The missing piece would be to only account for each id of each type .缺少的部分是只考虑每种type的每个id

You need to group again by the id , take the head from each subgroup, flatten, and then apply the spec:您需要按id再次分组,从每个子组中取出头部,展平,然后应用规范:

 const { pipe, groupBy, prop, values, map, applySpec, head, ifElse, any, always, filter, propEq, length } = R const fn = pipe( groupBy(prop('type')), values, map(pipe( groupBy(prop('id')), values, map(applySpec({ name: pipe(head, prop('type')), value: ifElse(any(propEq('value', 'ON')), always('ON'), always('OFF')), })), applySpec({ name: pipe(head, prop('name')), enabled: pipe(filter(propEq('value', 'ON')), length), disabled: pipe(filter(propEq('value', 'OFF')), length), }) )), ) const arr = [{"id":1,"value":"ON","type":"TYPE_1"},{"id":1,"value":"OFF","type":"TYPE_1"},{"id":2,"value":"ON","type":"TYPE_1"},{"id":3,"value":"OFF","type":"TYPE_2"},{"id":3,"value":"OFF","type":"TYPE_2"},{"id":3,"value":"OFF","type":"TYPE_2"}] const result = fn(arr) console.log(result)
 <script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.27.0/ramda.js"></script>

Try this:尝试这个:

const transform = applySpec({
  name: head,
  enabled: pipe(last, filter(propEq('value', 'ON')), length),
  disabled: pipe(last, filter(propEq('value', 'OFF')), length),
})
const fn = pipe(groupBy(prop('type')), toPairs, map(transform))

demo 演示

Here's another approach, somwhat different from the one by OriDrori.这是另一种方法,与 OriDrori 的方法有些不同。 It matches the given case, but I'm still not certain about the general rules, so it's possible that this doesn't actually capture the requirements properly.它与给定的情况相匹配,但我仍然不确定一般规则,因此这可能实际上并没有正确捕获需求。

 const extract = pipe ( groupBy (toString), // {JSON_key1: [{id, value, type}, {id, value, type}, ...] JSON_key2: [{id, value, type}, ...], ...} map (head), // {JSON_key1: {id, value, type}, JSON_key2: {id, value, type}, ...} values, // [{id, value, type}, {id, value, type}, ...] groupBy (prop ('type')), // {TYPE_1: [{id, value, type}, {id, value, type}, ...], "TYPE_2":[{id, value, type}]} map (countBy (prop ('value'))), // {TYPE_1: {ON: 2, OFF: 1}, TYPE_2: {OFF: 1}} toPairs, // [[TYPE_1, {ON: 2, OFF: 1}], [TYPE_2, {OFF: 1}]] map (applySpec ({ type: nth(0), enabled: pathOr(0, [1, 'ON']), disabled: pathOr(0, [1, 'OFF']) })) // [{type: "TYPE_1", enabled: 2, disabled: 1}, {type: "TYPE_2", enabled: 0, disabled: 1}] ) const data = [{id: 1, value: "ON", type: "TYPE_1"}, {id: 1, value: "OFF", type: "TYPE_1"}, {id: 2, value: "ON", type: "TYPE_1"}, {id: 3, value: "OFF", type: "TYPE_2"}, {id: 3, value: "OFF", type: "TYPE_2"}, {id: 3, value: "OFF", type: "TYPE_2"}]; console.log (extract (data))
 <script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.27.0/ramda.js"></script> <script> const {pipe, groupBy, toString, map, head, values, prop, countBy, toPairs, applySpec, nth, pathOr} = R </script>

Ramda's toString is not particularly fast. Ramda 的toString并不是特别快。 If you preferred, you could replace the first line of the pipeline with something like this:如果您愿意,可以将管道的第一行替换为以下内容:

  groupBy (({id, value, type}) => `${id}|${value}|${type}`),

Also, the map(applySpec) lines feel a bit complex.此外, map(applySpec)行感觉有点复杂。 We could replace them with something like this:我们可以用这样的东西替换它们:

  map (([type, {OFF: disabled = 0, ON: enabled = 0}]) => ({type, enabled, disabled}))

Note the style of a pipeline of small, relatively simple individual transformations.请注意小型、相对简单的单个转换管道的样式。 This to me is Ramda's sweet spot.这对我来说是 Ramda 的最佳选择。 Ramda is designed to support many different styles of functional programming, but this style is most central. Ramda 旨在支持许多不同的 styles 函数式编程,但这种风格是最核心的。

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

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