使用 Lodash 进行深度合并

Posted

技术标签:

【中文标题】使用 Lodash 进行深度合并【英文标题】:Deep Merge using Lodash 【发布时间】:2017-01-07 20:05:23 【问题描述】:

我有两个对象数组,其中包含具有标签的地址和实际地址的对象:

var originalAddresses = [
  
    label: 'home',
    address:  city: 'London', zipCode: '12345' 
  ,
  
    label: 'work',
    address:  city: 'New York', zipCode: '54321' 
  
];

var updatedAddresses = [
  
    label: 'home',
    address:  city: 'London (Central)', country: 'UK' 
  ,
  
    label: 'spain',
    address:  city: 'Madrid', zipCode: '55555' 
  
];

现在我想通过label 合并这些数组并比较地址的各个属性并仅合并新地址中实际存在的属性。所以结果应该是这样的:

var result = [
  
    label: 'home',
    address:  city: 'London (Central)', zipCode: '12345', country: 'UK' 
  ,
  
    label: 'work',
    address:  city: 'New York', zipCode: '54321' 
  ,
  
    label: 'spain',
    address:  city: 'Madrid', zipCode: '55555' 
  
]

如何使用lodash 来做到这一点? 我尝试了unionBy()merge() 的组合。使用 unionBy() 我可以按标签比较和连接数组,但这总是会替换整个对象。我可以确定合并地址,但这不会按标签发生。

【问题讨论】:

【参考方案1】:

您可以使用_.keyBy(arr, 'label') 将两个数组转换为对象,然后使用_.merge() 进行深度合并:

var originalAddresses = [
  label: 'home',
  address: 
    city: 'London',
    zipCode: '12345'
  
, 
  label: 'work',
  address: 
    city: 'New York',
    zipCode: '54321'
  
];

var updatedAddresses = [
  label: 'home',
  address: 
    city: 'London (Central)',
    country: 'UK'
  
, 
  label: 'spain',
  address: 
    city: 'Madrid',
    zipCode: '55555'
  
];

var result = _.values(_.merge(
  _.keyBy(originalAddresses, 'label'),
  _.keyBy(updatedAddresses, 'label')
));

console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.15.0/lodash.min.js"></script>

【讨论】:

【参考方案2】:

我尝试使用 VanillaJS 来处理这个问题。

const originalAddresses = [
    label: 'home',
    address: 
        city: 'London',
        zipCode: '12345'
    
, 
    label: 'work',
    address: 
        city: 'New York',
        zipCode: '54321'
    
];

const updatedAddresses = [
    label: 'home',
    address: 
        city: 'London (Central)',
        country: 'UK'
    
, 
    label: 'spain',
    address: 
        city: 'Madrid',
        zipCode: '55555'
    
];


const groupBy = (array, property) => 
    return array.reduce((acc, cur) => 
            let key = cur[property]
            if (!acc[key]) 
                acc[key] = []
            
            acc[key].push(cur)

            return acc
        
        , )


const groupByLabel = groupBy([...originalAddresses, ...updatedAddresses], 'label')

const result  = Object.keys(groupByLabel).map((key) => 
        return 
            label: groupByLabel[key][0].label,
            address: groupByLabel[key].reduce((acc, cur) => 
                    return Object.assign(acc, cur.address)
                
                , )
        
    
)
console.log(result)

【讨论】:

【参考方案3】:

您可以使用 _.keyBy(arr, 'label') 将两个数组转换为对象,然后使用 _.merge() 进行深度合并:

var originalAddresses = [
  label: 'home',
  address: 
    city: 'London',
    zipCode: '12345'
  
, 
  label: 'work',
  address: 
    city: 'New York',
    zipCode: '54321'
  
];

var updatedAddresses = [
  label: 'home',
  address: 
    city: 'London (Central)',
    country: 'UK'
  
, 
  label: 'spain',
  address: 
    city: 'Madrid',
    zipCode: '55555'
  
];

var result = _.values(_.merge(
  _.keyBy(originalAddresses, 'label'),
  _.keyBy(updatedAddresses, 'label')
));

console.log(result);

【讨论】:

不错...复制?

以上是关于使用 Lodash 进行深度合并的主要内容,如果未能解决你的问题,请参考以下文章

javascript 两个对象之间的深度差异,使用lodash

Lodash 合并:仅在源值与目标值匹配时复制对象属性

Lodash - 深度类型验证

项目中使用过的lodash方法总结

使用传播算子深度合并对象

使用deepMerge库深度合并两个对象可枚举属性