Ramda - преобразование массива по нескольким группам - PullRequest
0 голосов
/ 04 мая 2020

Я пытаюсь выполнить sh следующее, используя ramda:

Вот пример того, как 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"
  }
]

Вот как я хочу это посмотреть:

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

В основном мне нужно сгруппировать по type и id, где их комбинация может повторяться, но учитывать только один.

Вот что я уже попытка:

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) 

Но это не работает, так как это возвращает следующее:

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

Недостающая часть должна учитывать только каждый id каждого type.

Ответы [ 3 ]

2 голосов
/ 05 мая 2020

Вам нужно снова сгруппировать по id, взять голову из каждой подгруппы, сгладить, а затем применить spe c:

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>
1 голос
/ 04 мая 2020

Попробуйте это:

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))

демо

0 голосов
/ 05 мая 2020

Вот еще один подход, несколько отличный от подхода ОриДрори. Он соответствует данному случаю, но я все еще не уверен в общих правилах, поэтому возможно, что это на самом деле не соответствует требованиям.

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 toString не особенно быстр. При желании вы можете заменить первую строку конвейера на что-то вроде этого:

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

Кроме того, строки map(applySpec) кажутся немного сложными. Мы могли бы заменить их чем-то вроде этого:

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

Обратите внимание на стиль конвейера небольших, относительно простых индивидуальных преобразований. Для меня это сладкое место Рамды. Ramda поддерживает множество различных стилей функционального программирования, но этот стиль является наиболее важным.

...