Ramda - 通过多个分组转换数组
Ramda - Transform array by multiple groupings
我正在尝试使用 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)
但它不起作用,因为 returns 以下内容:
[
{
name: "TYPE_1",
enabled: 2,
disabled: 1
},
{
type: "TYPE_2",
enabled: 0,
disabled: 3
]
缺少的部分将仅占每个 type
中的每个 id
。
试试这个:
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))
您需要再次按 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>
这是另一种方法,与 OriDrori 的方法略有不同。它符合给定的情况,但我仍然不确定一般规则,因此这可能实际上没有正确捕获要求。
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 的甜蜜点。 Ramda 旨在支持许多不同风格的函数式编程,但这种风格是最核心的。
我正在尝试使用 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)
但它不起作用,因为 returns 以下内容:
[
{
name: "TYPE_1",
enabled: 2,
disabled: 1
},
{
type: "TYPE_2",
enabled: 0,
disabled: 3
]
缺少的部分将仅占每个 type
中的每个 id
。
试试这个:
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))
您需要再次按 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>
这是另一种方法,与 OriDrori 的方法略有不同。它符合给定的情况,但我仍然不确定一般规则,因此这可能实际上没有正确捕获要求。
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 的甜蜜点。 Ramda 旨在支持许多不同风格的函数式编程,但这种风格是最核心的。