Javascript 基于键的Ramda递归合并&x27;比赛

Javascript 基于键的Ramda递归合并&x27;比赛,javascript,recursion,functional-programming,ramda.js,Javascript,Recursion,Functional Programming,Ramda.js,我有两个节点列表,形状如下: interface TreeNode { data: { name: string, sharedProp: boolean, oldProp: boolean }, children: TreeNode[], parents: TreeNode[], thereAreSomeShallowProps: any, } 完整的数据集将是TreeNode 我想要的是有一个函数,我可

我有两个节点列表,形状如下:

interface TreeNode {
    data: {
        name: string,
        sharedProp: boolean,
        oldProp: boolean
    },
    children: TreeNode[],
    parents: TreeNode[],
    thereAreSomeShallowProps: any,
}
完整的数据集将是
TreeNode

我想要的是有一个函数,我可以遍历这棵树,将
changes
树中的更改合并到基本树中。它需要的一些功能:

  • 匹配指定键的值(在本例中支持多级键),并合并匹配项
    • 可能使用
      flatten
      groupBy
  • 当对象的值是数组时,递归
  • 抗循环引用
  • 能够处理非常大的对象(至少超过100k个节点)
我看过的一些函数(但不确定如何组合起来构建我想要的函数):

  • applySpec
  • groupBy
  • mergeWithKey
  • mergeDeepWithKey

通过一些测试,可以更好地解释我试图实现的目标。虽然这可能不是最好的方法,但我们可以利用家里现有的工具轻松构建。(在我的例子中,我在这里自由使用了Ramda函数,因为问题被标记为Ramda(免责声明:我是Ramda的作者),但下面我展示了一个替代版本,它从头开始构建所需的实用程序函数

这就假设您的更改对象将是和/或将包括稀疏数组。如果没有,你打算如何匹配

我的做法如下:

//帮助程序或实用程序函数
函数*getpath(o,p=[])){
如果(Object(o)!==o | | Object.keys(o).length==0)产生p
if(对象(o)==o)
for(设k为对象键(o))
收益率*getpath(o[k],…p,Number.isInteger(Number(k))?Number(k):k])
}
常量所有路径=(o)=>[…获取路径(o)]
//主要功能
常量applyChanges=(对象,更改)=>
reduce((o,p)=>assocPath(p,path(p,changes),o),obj,allpath(changes))
//样本数据
常数基=[
{a:1,b:{c:11,d:[{e:100},{e:111}]},
{a:2,b:{c:22,d:[{e:200},{e:222}]},
{a:3,b:{c:33,d:[{e:300},{e:333}]},
]
常数三角洲=[
{a:8,b:{d:[,{e:888}]},
,
{b:{c:99,d:[{e:999},]},
]
//示范
控制台日志(
应用更改(基础、三角洲)
)


const{reduce,assocPath,path}=R
这个问题最好分成更小的部分,我不知道为什么需要使用Ramda来解决这个问题?Ramda是一个库,而不是一个框架。您对数组的更改是否稀疏?更好的是,你能提供一个小样本输入和预期的输出吗?@ScottSauyet,它有一些testsHm,我应该注意,主对象有超过100k个节点,每个节点都引用它的父节点和子节点。我担心,由于循环引用,尝试查找所有路径可能会有问题,并且遍历整个对象可能会花费太长时间(它需要对频繁的用户操作做出非常灵敏的响应),如果您的更改集有那么多节点,那么这可能是个问题。我不认为这是主要目标的问题。但是父/子链接可能会接受这种方法,或者至少需要一些自定义的
getpath
——跳过子节点。这些更改可能不会有那么多节点,但主树不认为有可能对这种方法进行增强,以处理这些问题。但最有效的方法是偏离Ramda的非修改理想。我想我可能可以使用一个参数来定义它应该或不应该遵循的键,以避免循环引用问题