使用 Ramda 减少对象数组中的多个属性并省略其他属性
Reduce multiple properties in array of array of objects and omit other properties using Ramda
我有这个包含对象的数组:
const data = [
[
{
index: 320,
blocks: 2,
value: '31011784785',
participants: 1222,
cost: '1286828506'
},
{
index: 319,
blocks: 0,
value: '111306385',
participants: 18,
cost: '0'
},
{
index: 318,
blocks: 0,
value: '14550473',
participants: 10,
cost: '0'
}
],
[
{
index: 320,
blocks: 1,
value: '7089001673',
participants: 492,
cost: '648196615'
},
{
index: 319,
blocks: 0,
value: '13551137',
participants: 8,
cost: '0'
},
{
index: 318,
blocks: 0,
value: '11499815',
participants: 5,
cost: '0'
}
],
[
{
index: 320,
blocks: 1,
value: '408900161',
participants: 200,
cost: '648196615'
},
{
index: 319,
blocks: 0,
value: '23551231',
participants: 10,
cost: '0'
},
{
index: 318,
blocks: 0,
value: '104324219',
participants: 5,
cost: '0'
}
]
]
我想创建一个包含对象的数组,这些对象将仅具有属性索引、值和参与者,其中值和参与者将是 3 个数组的总和。例如:
[
{
index: 320,
value: 38509686619,
participants: 1914,
},
{
index: 319,
value: 148408753,
participants: 36,
},
{
...
}
]
我还希望值字段是 BigInt。
受此启发我做了一些有用的东西,但是太长太麻烦了。
这个问题与 不同,因为我需要两个对象 属性 值,但我不知道该怎么做。
扁平化后,数组的数组,你应该映射和选择想要的属性并将values
转换为数字,然后分组,并将每个组组合成一个对象。
const { mergeWithKey, pipe, flatten, map, pick, evolve, groupBy, prop, reduce, values } = R
// merge deep and combine properties value
const combine = mergeWithKey((k, l, r) => k === 'value' || k === 'participants' ? l + r : r)
const mergeData = pipe(
flatten, // flatten to a single array
map(pipe(
pick(['index', 'value', 'participants']), // pick wanted properties
evolve({ value: Number }) // convert values to a number
)),
groupBy(prop('index')), // group by the name
map(reduce(combine, {})), // combine each group to a single object
values, // convert back to array
)
const data = [[{"index":320,"blocks":2,"value":"31011784785","participants":1222,"cost":"1286828506"},{"index":319,"blocks":0,"value":"111306385","participants":18,"cost":"0"},{"index":318,"blocks":0,"value":"14550473","participants":10,"cost":"0"}],[{"index":320,"blocks":1,"value":"7089001673","participants":492,"cost":"648196615"},{"index":319,"blocks":0,"value":"13551137","participants":8,"cost":"0"},{"index":318,"blocks":0,"value":"11499815","participants":5,"cost":"0"}],[{"index":320,"blocks":1,"value":"408900161","participants":200,"cost":"648196615"},{"index":319,"blocks":0,"value":"23551231","participants":10,"cost":"0"},{"index":318,"blocks":0,"value":"104324219","participants":5,"cost":"0"}]]
const results = mergeData(data)
console.log(results)
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.27.1/ramda.min.js" integrity="sha512-rZHvUXcc1zWKsxm7rJ8lVQuIr1oOmm7cShlvpV0gWf0RvbcJN6x96al/Rp2L2BI4a4ZkT2/YfVe/8YvB2UHzQw==" crossorigin="anonymous"></script>
普通 JS 解决方案:
const data = [[{"index":320,"blocks":2,"value":"31011784785","participants":1222,"cost":"1286828506"},{"index":319,"blocks":0,"value":"111306385","participants":18,"cost":"0"},{"index":318,"blocks":0,"value":"14550473","participants":10,"cost":"0"}],[{"index":320,"blocks":1,"value":"7089001673","participants":492,"cost":"648196615"},{"index":319,"blocks":0,"value":"13551137","participants":8,"cost":"0"},{"index":318,"blocks":0,"value":"11499815","participants":5,"cost":"0"}],[{"index":320,"blocks":1,"value":"408900161","participants":200,"cost":"648196615"},{"index":319,"blocks":0,"value":"23551231","participants":10,"cost":"0"},{"index":318,"blocks":0,"value":"104324219","participants":5,"cost":"0"}]];
const result = Object.values(data.flat()
.reduce((acc, { index, value, participants }) => {
acc[index] ??= { index, value: 0, participants: 0 };
acc[index].value += Number(value);
acc[index].participants += Number(participants);
return acc;
}, {}));
console.log(result);
.as-console-wrapper{min-height: 100%!important; top: 0}
此解决方案(使用 JS 而不是 rambda)尝试使用 BigInt 并将值提供到名为 valueB
的道具中。
const groupAndSum = arr => (
Object.values(
arr.flat().reduce(
(acc, {index, value, participants}) => ({
...acc,
[index]: {
index,
valueB: BigInt((acc[index]?.valueB ?? 0)) + BigInt(value), // valueB as big-int
value: (acc[index]?.value || 0) + +value, // value as a "Number"
participants: (acc[index]?.participants ?? 0) + +participants
}
}),
{}
)
).map( // to display big-int in the console within stack-snippets
({valueB, ...rest}) => ({valueB: valueB.toString(), ...rest})
)
);
const data = [
[
{
index: 320,
blocks: 2,
value: '31011784785',
participants: 1222,
cost: '1286828506'
},
{
index: 319,
blocks: 0,
value: '111306385',
participants: 18,
cost: '0'
},
{
index: 318,
blocks: 0,
value: '14550473',
participants: 10,
cost: '0'
}
],
[
{
index: 320,
blocks: 1,
value: '7089001673',
participants: 492,
cost: '648196615'
},
{
index: 319,
blocks: 0,
value: '13551137',
participants: 8,
cost: '0'
},
{
index: 318,
blocks: 0,
value: '11499815',
participants: 5,
cost: '0'
}
],
[
{
index: 320,
blocks: 1,
value: '408900161',
participants: 200,
cost: '648196615'
},
{
index: 319,
blocks: 0,
value: '23551231',
participants: 10,
cost: '0'
},
{
index: 318,
blocks: 0,
value: '104324219',
participants: 5,
cost: '0'
}
]
];
console.log(groupAndSum(data));
说明
Object.values()
用于从以下操作中提取 resulting-object 的值
- 首先,输入数组
flat
倾向于去除嵌套
- 接下来用
.reduce
遍历数组,生成一个result-object
acc
是 accumulator/aggregator 对象
- 每个
index
要么作为新键添加到 acc
中,其值为实际对象
- 如果
index
已经出现在 acc
中,那么 value
和 participants
道具是 summed-up.
valueB
是一个新的prop,用于存储value
的BigInt
格式
额外的 .map()
用于使 valueB
可在 stack-snippets 上的 console.log
中显示。这在原始代码中可能不需要 - 所以请忽略。
一种 Ramda 方法:
const convert = pipe (
transpose,
map (xs => ({
index: xs [0] .index,
value: xs .reduce ((a, {value}) => a + Number (value), 0),
participants: sum (pluck ('participants') (xs))
}))
)
const data = [[{index: 320, blocks: 2, value: "31011784785", participants: 1222, cost: "1286828506"}, {index: 319, blocks: 0, value: "111306385", participants: 18, cost: "0"}, {index: 318, blocks: 0, value: "14550473", participants: 10, cost: "0"}], [{index: 320, blocks: 1, value: "7089001673", participants: 492, cost: "648196615"}, {index: 319, blocks: 0, value: "13551137", participants: 8, cost: "0"}, {index: 318, blocks: 0, value: "11499815", participants: 5, cost: "0"}], [{index: 320, blocks: 1, value: "408900161", participants: 200, cost: "648196615"}, {index: 319, blocks: 0, value: "23551231", participants: 10, cost: "0"}, {index: 318, blocks: 0, value: "104324219", participants: 5, cost: "0"}]]
console .log (convert (data))
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.28.0/ramda.min.js"></script>
<script> const {pipe, transpose, map, sum, pluck, reduce, applySpec} = R </script>
我们从 transpose
开始,这使它变得更容易使用格式。然后对于每个新行,我们从第一条记录中获取索引,并对参与者和值求和。
因为 BigInt 在 SO 控制台中显示不佳,我跳过了它们,但变化很小:
- value: xs .reduce ((a, {value}) => a + Number (value), 0),
+ value: xs .reduce ((a, {value}) => a + BigInt(value), BigInt(0)),
一个point-free版本,如果你有那个癖好,也不会更难:
const convert = pipe (
transpose,
map (applySpec ({
index: pipe (head, prop ('index')),
value: reduce ((a, {value}) => a + Number (value), 0),
// value: reduce ((a, {value}) => a + BigInt (value), BigInt (0)),
participants: pipe (pluck ('participants'), sum)
}))
)
我有这个包含对象的数组:
const data = [
[
{
index: 320,
blocks: 2,
value: '31011784785',
participants: 1222,
cost: '1286828506'
},
{
index: 319,
blocks: 0,
value: '111306385',
participants: 18,
cost: '0'
},
{
index: 318,
blocks: 0,
value: '14550473',
participants: 10,
cost: '0'
}
],
[
{
index: 320,
blocks: 1,
value: '7089001673',
participants: 492,
cost: '648196615'
},
{
index: 319,
blocks: 0,
value: '13551137',
participants: 8,
cost: '0'
},
{
index: 318,
blocks: 0,
value: '11499815',
participants: 5,
cost: '0'
}
],
[
{
index: 320,
blocks: 1,
value: '408900161',
participants: 200,
cost: '648196615'
},
{
index: 319,
blocks: 0,
value: '23551231',
participants: 10,
cost: '0'
},
{
index: 318,
blocks: 0,
value: '104324219',
participants: 5,
cost: '0'
}
]
]
我想创建一个包含对象的数组,这些对象将仅具有属性索引、值和参与者,其中值和参与者将是 3 个数组的总和。例如:
[
{
index: 320,
value: 38509686619,
participants: 1914,
},
{
index: 319,
value: 148408753,
participants: 36,
},
{
...
}
]
我还希望值字段是 BigInt。
受此启发
这个问题与
扁平化后,数组的数组,你应该映射和选择想要的属性并将values
转换为数字,然后分组,并将每个组组合成一个对象。
const { mergeWithKey, pipe, flatten, map, pick, evolve, groupBy, prop, reduce, values } = R
// merge deep and combine properties value
const combine = mergeWithKey((k, l, r) => k === 'value' || k === 'participants' ? l + r : r)
const mergeData = pipe(
flatten, // flatten to a single array
map(pipe(
pick(['index', 'value', 'participants']), // pick wanted properties
evolve({ value: Number }) // convert values to a number
)),
groupBy(prop('index')), // group by the name
map(reduce(combine, {})), // combine each group to a single object
values, // convert back to array
)
const data = [[{"index":320,"blocks":2,"value":"31011784785","participants":1222,"cost":"1286828506"},{"index":319,"blocks":0,"value":"111306385","participants":18,"cost":"0"},{"index":318,"blocks":0,"value":"14550473","participants":10,"cost":"0"}],[{"index":320,"blocks":1,"value":"7089001673","participants":492,"cost":"648196615"},{"index":319,"blocks":0,"value":"13551137","participants":8,"cost":"0"},{"index":318,"blocks":0,"value":"11499815","participants":5,"cost":"0"}],[{"index":320,"blocks":1,"value":"408900161","participants":200,"cost":"648196615"},{"index":319,"blocks":0,"value":"23551231","participants":10,"cost":"0"},{"index":318,"blocks":0,"value":"104324219","participants":5,"cost":"0"}]]
const results = mergeData(data)
console.log(results)
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.27.1/ramda.min.js" integrity="sha512-rZHvUXcc1zWKsxm7rJ8lVQuIr1oOmm7cShlvpV0gWf0RvbcJN6x96al/Rp2L2BI4a4ZkT2/YfVe/8YvB2UHzQw==" crossorigin="anonymous"></script>
普通 JS 解决方案:
const data = [[{"index":320,"blocks":2,"value":"31011784785","participants":1222,"cost":"1286828506"},{"index":319,"blocks":0,"value":"111306385","participants":18,"cost":"0"},{"index":318,"blocks":0,"value":"14550473","participants":10,"cost":"0"}],[{"index":320,"blocks":1,"value":"7089001673","participants":492,"cost":"648196615"},{"index":319,"blocks":0,"value":"13551137","participants":8,"cost":"0"},{"index":318,"blocks":0,"value":"11499815","participants":5,"cost":"0"}],[{"index":320,"blocks":1,"value":"408900161","participants":200,"cost":"648196615"},{"index":319,"blocks":0,"value":"23551231","participants":10,"cost":"0"},{"index":318,"blocks":0,"value":"104324219","participants":5,"cost":"0"}]];
const result = Object.values(data.flat()
.reduce((acc, { index, value, participants }) => {
acc[index] ??= { index, value: 0, participants: 0 };
acc[index].value += Number(value);
acc[index].participants += Number(participants);
return acc;
}, {}));
console.log(result);
.as-console-wrapper{min-height: 100%!important; top: 0}
此解决方案(使用 JS 而不是 rambda)尝试使用 BigInt 并将值提供到名为 valueB
的道具中。
const groupAndSum = arr => (
Object.values(
arr.flat().reduce(
(acc, {index, value, participants}) => ({
...acc,
[index]: {
index,
valueB: BigInt((acc[index]?.valueB ?? 0)) + BigInt(value), // valueB as big-int
value: (acc[index]?.value || 0) + +value, // value as a "Number"
participants: (acc[index]?.participants ?? 0) + +participants
}
}),
{}
)
).map( // to display big-int in the console within stack-snippets
({valueB, ...rest}) => ({valueB: valueB.toString(), ...rest})
)
);
const data = [
[
{
index: 320,
blocks: 2,
value: '31011784785',
participants: 1222,
cost: '1286828506'
},
{
index: 319,
blocks: 0,
value: '111306385',
participants: 18,
cost: '0'
},
{
index: 318,
blocks: 0,
value: '14550473',
participants: 10,
cost: '0'
}
],
[
{
index: 320,
blocks: 1,
value: '7089001673',
participants: 492,
cost: '648196615'
},
{
index: 319,
blocks: 0,
value: '13551137',
participants: 8,
cost: '0'
},
{
index: 318,
blocks: 0,
value: '11499815',
participants: 5,
cost: '0'
}
],
[
{
index: 320,
blocks: 1,
value: '408900161',
participants: 200,
cost: '648196615'
},
{
index: 319,
blocks: 0,
value: '23551231',
participants: 10,
cost: '0'
},
{
index: 318,
blocks: 0,
value: '104324219',
participants: 5,
cost: '0'
}
]
];
console.log(groupAndSum(data));
说明
Object.values()
用于从以下操作中提取 resulting-object 的值- 首先,输入数组
flat
倾向于去除嵌套 - 接下来用
.reduce
遍历数组,生成一个result-object acc
是 accumulator/aggregator 对象- 每个
index
要么作为新键添加到acc
中,其值为实际对象 - 如果
index
已经出现在acc
中,那么value
和participants
道具是 summed-up. valueB
是一个新的prop,用于存储value
的
BigInt
格式
额外的 .map()
用于使 valueB
可在 stack-snippets 上的 console.log
中显示。这在原始代码中可能不需要 - 所以请忽略。
一种 Ramda 方法:
const convert = pipe (
transpose,
map (xs => ({
index: xs [0] .index,
value: xs .reduce ((a, {value}) => a + Number (value), 0),
participants: sum (pluck ('participants') (xs))
}))
)
const data = [[{index: 320, blocks: 2, value: "31011784785", participants: 1222, cost: "1286828506"}, {index: 319, blocks: 0, value: "111306385", participants: 18, cost: "0"}, {index: 318, blocks: 0, value: "14550473", participants: 10, cost: "0"}], [{index: 320, blocks: 1, value: "7089001673", participants: 492, cost: "648196615"}, {index: 319, blocks: 0, value: "13551137", participants: 8, cost: "0"}, {index: 318, blocks: 0, value: "11499815", participants: 5, cost: "0"}], [{index: 320, blocks: 1, value: "408900161", participants: 200, cost: "648196615"}, {index: 319, blocks: 0, value: "23551231", participants: 10, cost: "0"}, {index: 318, blocks: 0, value: "104324219", participants: 5, cost: "0"}]]
console .log (convert (data))
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.28.0/ramda.min.js"></script>
<script> const {pipe, transpose, map, sum, pluck, reduce, applySpec} = R </script>
我们从 transpose
开始,这使它变得更容易使用格式。然后对于每个新行,我们从第一条记录中获取索引,并对参与者和值求和。
因为 BigInt 在 SO 控制台中显示不佳,我跳过了它们,但变化很小:
- value: xs .reduce ((a, {value}) => a + Number (value), 0),
+ value: xs .reduce ((a, {value}) => a + BigInt(value), BigInt(0)),
一个point-free版本,如果你有那个癖好,也不会更难:
const convert = pipe (
transpose,
map (applySpec ({
index: pipe (head, prop ('index')),
value: reduce ((a, {value}) => a + Number (value), 0),
// value: reduce ((a, {value}) => a + BigInt (value), BigInt (0)),
participants: pipe (pluck ('participants'), sum)
}))
)