Javascript 属性上具有函数的多级groupby
这类似于,但有一个扭曲,这给我带来了麻烦。除了两级分组之外,我希望内部GROUPBY位于属性值的处理版本上 考虑如下数据:Javascript 属性上具有函数的多级groupby,javascript,ramda.js,Javascript,Ramda.js,这类似于,但有一个扭曲,这给我带来了麻烦。除了两级分组之外,我希望内部GROUPBY位于属性值的处理版本上 考虑如下数据: 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: 'jun
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"
}
]
}
}
我觉得有点傻,我不能得到这个。有什么想法吗?这不是使用ramda,而是使用vanilla JS
const data=[
{top:'top1',
名称:'junk-key-a-101'},
{top:'top1',
名称:'junk-key-b-102'},
{top:'top2',
名称:'junk-key-c-103'},
{top:'top2',
名称:'junk-key-c-104'}];
const res=数据减少((acc、val、ind、arr)=>{
const top=val.top;
//如果obj中不存在顶部,请创建它
如果(!acc[顶部]){
acc[top]={};
}
//通过拆分获取密钥。您也可以在此处使用正则表达式
const keyFragments=val.name.split('-');
常量键=[keyFragments[1],keyFragments[2]].join('-');
//如果关键obj道具尚不存在,请创建阵列
如果(!acc[顶部][键]){
acc[顶部][键]=[];
}
//推动价值
acc[top][key].push({name:val.name,top:val.top});
返回acc;
}, {});
控制台日志(res)代码>你们非常接近。只要将这些函数与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=管道(
groupBy(道具(“top”),
地图(groupBy(管道(道具(“名称”)、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(数据))
另一种方法是构造每个最终对象并合并它们:
可以变换此对象:
{
"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;
常量数据=[
{top:'top1',
名称:'junk-key-a-101'},
{top:'top1',
名称:'junk-key-b-102'},
{top:'top2',
名称:'junk-key-c-103'},
{top:'top2',
名称:'junk-key-c-104'}
];
常数键=切片(5,-4);
常量obj=({top,name})=>({
[上图]:{
[钥匙(姓名)]:[
{top,name}
]
}
});
const groupByTopTenZone=reduce(useWith(mergeDeepWith(concat),[identity,obj]),{});
console.log(
groupByTopTenZone(数据)
)
谢谢,@quirimo,感谢你花时间回答,这与我的非ramda解决方案非常相似(我想说的是非功能性的,但这不会是正确的)。没问题:)有时候我确实更喜欢香草js而不是这些框架,因为即使它们让你的工作非常简单,有时候你会在对象/数组上循环几次,也许你只需要一次迭代就可以完成任务谢谢Scott。这是一个很大的帮助。在实际数据中,为一个键使用名称是有点复杂的,分割片连接是一个更可靠的解决方案,但是,是的,寻求简化会有所帮助。我确实对管道的两种用途有些困惑。我觉得他们的工作方式和我完全相反。内部的一个感觉像道具(“名字”)进入片饲料。外部的“感觉”就像地图输入groupBy(道具(“顶部”))。我在这一点上显然是错误的,但这会阻止我自己提出类似的解决方案。你能让我走上正确的轨道吗?@KevinO'Connor:它们都按照你的直觉所说的方式工作。外部的一个首先按top
分组,产生{top1:[…],top2:[…]}
。然后对该结果调用map
。注意,map(square,{a:1,b:2,c:3})/=>{a:1,b:4,c:9}
。这与使用map
提供的函数转换对象中存储在top1
和top2
中的数组的方式相同,这里是内部groupBy(…)
。如果你真的想要另一个方向的东西,那就是它的镜像孪生兄弟。是的,我明白了。再次感谢,@ScottSauyet!我希望这有助于我以后更好地思考这个问题。我喜欢直接使用函数来创建对象。我曾经尝试过类似的方法(没有您添加的键方法),然后是evolve,但是在为后续的类似键的方法处理正确的项时增加了麻烦。谢谢你的另一种方法。