在忽略嵌套数组的同时深度合并两个不可变映射

Posted

技术标签:

【中文标题】在忽略嵌套数组的同时深度合并两个不可变映射【英文标题】:Deep merging two Immutable maps while ignoring nested arrays 【发布时间】:2021-05-28 22:43:46 【问题描述】:

const map1 = Immutable.Map( a:  x: 1, z: 1, y: 1, values: [1, 2, 3]  );
const map2 = Immutable.Map( a:  x: 2, values: [4, 5, 6]  );

const map3 = map1.mergeDeep(map2)

// Output I want is:
//  a:  x: 2, z: 1, y: 1 values: [4, 5, 6]  

假设我有两张地图。其中一张地图是另一张地图的部分对象,不一定包含所有相同的属性。我想合并它们,包括嵌套对象,但不合并数组。如上所示,它更新了两个地图中存在的属性,保留了新第二个地图中不存在的旧属性,并且只使用了最新的地图数组而不是将它们合并到 [1,2,3 ,4,5,6]。我该怎么做?

【问题讨论】:

【参考方案1】:

这个问题似乎与this *** 帖子有关。正如那里所说,使用fromJS 而不是Map 可以得到所需的结果。此外,this 回答很好地解释了两者之间的区别。请参考并运行下面的 sn-p 以获取工作示例:

const map1 = Immutable.fromJS( a:  x: 1, z: 1, y: 1, values: [1, 2, 3]  );
const map2 = Immutable.fromJS( a:  x: 2, values: [4, 5, 6]  );

const map3 = map1.mergeDeep(map2)

console.log(map3)

// Output I want is:
//  a:  x: 2, z: 1, y: 1 values: [4, 5, 6]  

/* And this snippet results in:

  "a": 
    "x": 2,
    "z": 1,
    "y": 1,
    "values": [
      4,
      5,
      6
    ]
  

*/
<script src="https://cdnjs.cloudflare.com/ajax/libs/immutable/3.8.2/immutable.js" integrity="sha512-9XVMKQr4ymAxO4jZVbEM2eq01aGlTY4bMlWyQh+KcQWprFkWu5KpOcDOa3RLFZc586QHihZPd1b8XzXqweRxIQ==" crossorigin="anonymous"></script>

【讨论】:

如果你运行它,你会看到值的长度为 6,我希望将数组替换为 [4,5,6],而不是合并 @GregM 我很困惑,如果你运行 sn-p,这正是你得到的,值数组被 [4,5,6] 替换。你在使用其他版本的 immutable 吗?【参考方案2】:

您没有说明您使用的 immutable.js 版本,但是您问的方式,它可能是 4.0.0-rc12。 Immutable.js 3.8.x 版本的 mergeDeep 函数做了你想要的;它替换了数组而不是合并它们。这就是为什么@etarhan 的答案有效但对您无效。

没有“好的”解决方案。 mergeDeepWith 函数让您定义一个合并函数,但遗憾的是合并仅在冲突时触发 - 所以它也对您没有帮助。您所能做的就是手动遍历对象或升级 immutable.js。

还请注意,Immutable.Map( a: x: 1, z: 1, y: 1, values: [1, 2, 3] ); 只会对输入进行浅层转换。 values 的数组仍然是一个数组。这通常是不希望的,您可能希望拥有一个 Immutable.List 而不是数组。为此,请使用 fromJS,它会转换 depply。

我会在 slack 频道上提出这个问题,IMO 应该也有可能在集合上调用合并。

类似的事情可能会完成这项工作:

const map1 = Immutable.fromJS( a:  x: 'one', z: 'old', y: 'old', values: [1, 2, 3]  );
const map2 = Immutable.fromJS( a:  x: 'two', v: 'new', values: [4, 5, 6]  );


function mergeStuff(a, b, path = '') 
  return a.withMutations(map => 
    for(key of b.keys()) 
      map.update(key, (val) => 
        console.log('updating', path + key, val, b.get(key));
        if(Immutable.isKeyed(val)) 
          return mergeStuff(val, b.get(key), key + '.');
        
        return b.get(key, val);
      );
    
  );


const map3 = mergeStuff(map1, map2);

console.log('result:');
console.log(map3);
<script src="https://cdnjs.cloudflare.com/ajax/libs/immutable/4.0.0-rc.12/immutable.js"></script>

【讨论】:

以上是关于在忽略嵌套数组的同时深度合并两个不可变映射的主要内容,如果未能解决你的问题,请参考以下文章

scala数据结构

在 React/Redux reducer 中,如何以不可变的方式更新嵌套数组中的字符串?

4.Scala-数据结构

集合

集合

Scala集合