Вот еще один подход, несколько отличный от подхода ОриДрори. Он соответствует данному случаю, но я все еще не уверен в общих правилах, поэтому возможно, что это на самом деле не соответствует требованиям.
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 поддерживает множество различных стилей функционального программирования, но этот стиль является наиболее важным.