如何根据值合并两个不同长度的对象

How can I merge two objects of different lengths based on the values

我有两个对象数组,两个数组都包含键值对。我的 objective 是分配键值,如果一个键 name 的字符串值与另一个键 _id 的字符串值匹配,则从一个数组到第二个数组。

我试过将两个数组组合成一个数组,并且只有一个数组包含对象,但我仍然不确定如何根据键的匹配值将键和值分配给其他对象_idname。我知道如何使用相同的键,但我们如何基于不同的键和相同的值来做到这一点? 这可能是糟糕的设计和实践,但这就是数据返回的方式。可行吗?我尝试过使用 lodash、传播操作、映射但没有成功。

arr1 = [
{"_id": "electronics", "number": 35 },
{"_id": "house Appliances", "number": 5 },
{"_id": "nothing", "number":0}
]

arr2 = [
{"name": "electronics", "purpose": "entertainment", "price": 100},
{"name": "house Appliances", "purpose": "general", "price": 200},
{"name": "watches", "purpose": "time", "price": 30} ]

combinedArrObj = [
{"name": "electronics", "number": 35, "purpose": "entertainment", "price": 100},
{"name": "house Appliances", "purpose": "general", "price": 200, "number": 5}, 
{"name": "watches", "purpose": "time", "price": 30}
 ]

您可以使用 reduce 和 find

  • 首先检查 arr1 中是否存在任何匹配的 _id 对应的名称
  • 如果它存在,我们将该元素的值合并到最终输出中
  • 否则只在输出中保留 inp

let arr1 = [{"_id": "electronics", "number": 35 },"_id": "house Appliances", "number": 5 }]

let arr2 = [{"name": "electronics", "purpose": "entertainment", "price": 100},{"name": "house Appliances", "purpose": "general", "price": 200},{"name": "watches", "purpose": "time", "price": 30} ]

let final = arr2.reduce((op,inp)=>{
  let found = arr1.find(({_id})=>_id===inp.name)
  let name = inp.name
  op[name] = op[name] || {}
  if(found){
    let {_id, ...rest} = found
    op[name] = {...op[name], ...rest, ...inp}
  } else {
    op[name] = {...op[name], ...inp}
  }
  return op
},{})

console.log(final)

使用 _.flow() that uses _.overArgs() to convert each array to object with it's respective identifier (_id or name) as key (with _.keyBy()), and merge them to a single object. Convert the object back to array, by mapping it while omitting _id 字段创建函数:

const { flow, partialRight: pr, overArgs, merge, keyBy, map, omit } = _

const combineArrays = flow(
  overArgs((...objs) => merge({}, ...objs), [
    arr1 => keyBy(arr1, '_id'),
    arr2 => keyBy(arr2, 'name')    
  ]),
  pr(map, o => omit(o, '_id'))
)

const arr1 = [{"_id": "electronics", "number": 35 }, {"_id": "house Appliances", "number": 5 }]
const arr2 = [{"name": "electronics", "purpose": "entertainment", "price": 100},{"name": "house Appliances", "purpose": "general", "price": 200},{"name": "watches", "purpose": "time", "price": 30}]
 
const combinedArrs = combineArrays(arr1, arr2)

console.log(combinedArrs)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.js"></script>

以及使用 lodash/fp 的简洁版本:

const { flow, overArgs, merge, keyBy, map, omit } = _

const combineArrays = flow(
  overArgs(merge, [keyBy('_id'), keyBy('name')]),
  map(omit('_id'))
)

const arr1 = [{"_id": "electronics", "number": 35 }, {"_id": "house Appliances", "number": 5 }]
const arr2 = [{"name": "electronics", "purpose": "entertainment", "price": 100},{"name": "house Appliances", "purpose": "general", "price": 200},{"name": "watches", "purpose": "time", "price": 30}]
 
const combinedArrs = combineArrays(arr1, arr2)

console.log(combinedArrs)
<script src='https://cdn.jsdelivr.net/g/lodash@4(lodash.min.js+lodash.fp.min.js)'></script>

使用 vanilla JS,你可以 concat the arrays, and then use Array.reduce() to convert the arrays to object using the _id or name as key, and combining items with the same key with object spread. Then convert back to array with Object.values():

const combineArrays = (arr1, arr2) => Object.values(
  arr1.concat(arr2) // combine the arrays
    .reduce((r, { _id, ...o }) => { // clone the object and remove _id if exists
      const key = _id || o.name // the key is the _id or the name if _id doesn't exist

      r[key] = r[key] ? { ...r[key], ...o } : o // if the key exists on the accumulator combine with current item, if not set current item to the key

      return r;
    }, {})
)

const arr1 = [{"_id": "electronics", "number": 35 }, {"_id": "house Appliances", "number": 5 }]
const arr2 = [{"name": "electronics", "purpose": "entertainment", "price": 100},{"name": "house Appliances", "purpose": "general", "price": 200},{"name": "watches", "purpose": "time", "price": 30}]
 
const combinedArrs = combineArrays(arr1, arr2)

console.log(combinedArrs)

在我看来,如果 一对 key value array1 中只有 一对 key value,则无需过于复杂化。只需转换为地图,然后 Array.map through array2 and Object.assign 即可创建没有 lodash 等的合并

const arr1 = [{"_id": "electronics", "number": 35 }, {"_id": "house Appliances", "number": 5 }]
const arr2 = [{"name": "electronics", "purpose": "entertainment", "price": 100},{"name": "house Appliances", "purpose": "general", "price": 200},{"name": "watches", "purpose": "time", "price": 30}]

let map = arr1.reduce((acc, {_id, number}) => (acc[_id] = number, acc), {})

let result = arr2.map(({name, ...rest}) => 
  Object.assign({ name }, rest, map[name] ? { number: map[name] } : {}))

console.log(result)