简体   繁体   中英

Ramda - Transform array by multiple groupings

I am trying to accomplish the following using ramda :

Here's a sample of what the array will look like:

[
  {
    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.

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 .

You need to group again by the id , take the head from each subgroup, flatten, and then apply the spec:

 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. 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. 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. 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 is designed to support many different styles of functional programming, but this style is most central.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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