这与multi level groupby ramda js相似,但有一种扭曲,给我带来麻烦。除了两级分组外,我还希望内部分组依据是经过处理的属性值版本。
考虑这样的数据:
const data = [
{ top: 'top1',
name: 'junk-key-a-101' },
{ top: 'top1',
name: 'junk-key-b-102' },
{ top: 'top2',
name: 'junk-key-c-103' },
{ top: 'top2',
name: 'junk-key-c-104' } ];
我可以拔出密钥,对其进行处理并使其独特,如下所示:
const getZoneFromName = n => join('-', slice(1, 3, split('-', n)));
uniq(map(getZoneFromName, pluck('name', data)));
这将为我提供一个不错的清单:
["key-a", "key-b", "key-c"]
我可以将列表分为两个级别:
const groupByTopThenZone = pipe(
groupBy(prop("top")),
map(groupBy(prop("name")))
);
groupByTopThenZone(data);
但是我无法弄清楚如何组合它们以获取以下输出:
{
top1: {
"key-a": [
{
name: "junk-key-a-101",
top: "top1"
}
],
"key-b": [
{
name: "junk-key-b-102",
top: "top1"
}
]
},
top2: {
"key-c": [
{
name: "junk-key-c-103",
top: "top2"
},
{
name: "junk-key-c-104",
top: "top2"
}
]
}
}
我感觉有点傻,我无法得到这个。有任何想法吗? Here是一个玩耍的地方。
答案 0 :(得分:1)
您非常亲密。只需将这些功能与compose
/ pipe
结合即可达到目的。
(请注意,这里也是getZoneFromName
的简化版本。)
const {pipe, groupBy, map, prop, slice} = R
//const getZoneFromName = n => join('-', slice(1, 3, split('-', n)));
const getZoneFromName = slice(5, -4)
const groupByTopThenZone = pipe(
groupBy(prop("top")),
map(groupBy(pipe(prop("name"), getZoneFromName)))
)
const data = [{"name": "junk-key-a-101", "top": "top1"}, {"name": "junk-key-b-102", "top": "top1"}, {"name": "junk-key-c-103", "top": "top2"}, {"name": "junk-key-c-104", "top": "top2"}]
console.log(groupByTopThenZone(data))
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script>
此功能当然可以简化很多,内联起来可能更容易:
const groupByTopThenZone = pipe(
groupBy(prop("top")),
map(groupBy(pipe(prop("name"), slice(5, -4)))
)
要记住的主要事情是groupBy
不一定与prop
捆绑在一起。我们可以对 any String
/ Number
/ Symbol
生成函数的结果进行分组。
答案 1 :(得分:0)
这不是使用ramda,而是使用香草JS。
const data = [
{ top: 'top1',
name: 'junk-key-a-101' },
{ top: 'top1',
name: 'junk-key-b-102' },
{ top: 'top2',
name: 'junk-key-c-103' },
{ top: 'top2',
name: 'junk-key-c-104' } ];
const res = data.reduce((acc, val, ind, arr) => {
const top = val.top;
// if the top does not exist in the obj, create it
if (!acc[top]) {
acc[top] = {};
}
// get the key through split. you could also use a regex here
const keyFragments = val.name.split('-');
const key = [keyFragments[1], keyFragments[2]].join('-');
// if the key obj prop does not exist yet, create the array
if (!acc[top][key]) {
acc[top][key] = [];
}
// push the value
acc[top][key].push({ name: val.name, top: val.top });
return acc;
}, {});
console.log(res);
答案 2 :(得分:0)
另一种方法是构造每个最终对象并将其全部合并:
您可以变换此对象:
{
"top": "top1",
"name": "junk-key-a-101"
}
进入这个:
{
"top1": {
"key-a": [
{
"name": "junk-key-a-101",
"top": "top1"
}
]
}
}
具有以下功能:
const key = slice(5, -4);
const obj = ({top, name}) => ({
[top]: {
[key(name)]: [
{top, name}
]
}
});
因此,现在您可以迭代数据,转换每个对象并将它们合并在一起:
const groupByTopTenZone = reduce(useWith(mergeDeepWith(concat), [identity, obj]), {});
完整示例:
const {slice, useWith, identity, reduce, mergeDeepWith, concat} = R;
const data = [
{ top: 'top1',
name: 'junk-key-a-101' },
{ top: 'top1',
name: 'junk-key-b-102' },
{ top: 'top2',
name: 'junk-key-c-103' },
{ top: 'top2',
name: 'junk-key-c-104' }
];
const key = slice(5, -4);
const obj = ({top, name}) => ({
[top]: {
[key(name)]: [
{top, name}
]
}
});
const groupByTopTenZone = reduce(useWith(mergeDeepWith(concat), [identity, obj]), {});
console.log(
groupByTopTenZone(data)
)
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script>