从另一个对象插入嵌套属性

时间:2018-11-30 23:18:39

标签: javascript ramda.js

我有两个数组metaObjectsjustObjects

两个数组中的这些对象共有id属性。

我想创建一个新数组,将来自不同数组中对象的属性组合起来

const metaObjects = [
  {
    id: 1,
    metaProp: "metaProp1"
  },
  {
    id: 2,
    metaProp: "metaProp2"
  }
];

const justObjects = [
  {
    id: 1,
    justProp: "justProp1"
  },
  {
    id: 2,
    justProp: "justProp2"
  }
];

这是我期望的结果

const result= [
    {
      id: 1,
      metaProp: "metaProp1",
      justProp: "justProp1"
    },
    {
      id: 2,
      metaProp: "metaProp2",
      justProp: "justProp2"
    }
  ];

我试图实现map of map来实现这一目标

const combinedObject = justObjects.map(_w => {
  return metaObjects.map(_m => {
    if (_w.id === _m.id) {
      return { ..._m, ..._w };
    }
  });
}, metaObjects);

console.log(combinedObject);

但是我收到以下错误

[ [ { id: 1, metaProp: 'metaProp1', justProp: 'justProp1' },
    undefined ],
  [ undefined,
    { id: 2, metaProp: 'metaProp2', justProp: 'justProp2' } ] ]

我不确定为什么每个数组的内部数组中都有一个undefined
另外,我需要弄平数组,使其接近上面的预期结果。

我听说过ramda的lens可组合功能

可以在这里使用吗?

4 个答案:

答案 0 :(得分:1)

这与customcommander的答案非常相似,但是选择使用groupByvalues而不是sortBygroupWith。这对我来说更合乎逻辑,尤其是避免了不必要的sort通话。

const {pipe, concat, groupBy, prop, values, map, mergeAll} = R

const joinOnId = pipe
  ( concat
  , groupBy (prop ('id'))
  , values
  , map (mergeAll)
  )

const metaObjects = 
  [ { id: 1, metaProp: "metaProp1" }
  , { id: 2, metaProp: "metaProp2" }
  , { id: 3, metaProp: "metaProp3" }  // unique to `meta`
  ]

const justObjects = 
  [ { id: 1, justProp: "justProp1" }
  , { id: 2, justProp: "justProp2" }
  , { id: 4, justProp: "justProp4" }  // unique to `just`
  ]

console.log 
  ( joinOnId (metaObjects, justObjects)
  )
.as-console-wrapper {
  max-height: 100vh !important;
}
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script>

请注意,可以轻松调整以接受其他属性名称:

const joinOn = (propName) =>
  pipe
    ( concat
    , groupBy (prop (propName))
    , values
    , map (mergeAll)
    )
// ...
const joinOnId = joinOn ('id')

或使用任何常见的密钥生成功能:

const joinOn = (keyFn) =>
  pipe
    ( concat
    , groupBy (keyFn)
    , values
    , map (mergeAll)
    )
// ...
const joinOnId = joinOn (prop ('id'))

答案 1 :(得分:0)

您可以搜索要与find()合并的对象,然后使用Object.assign()将它们合并在一起。假设该对象已经存在于metaObjects中,如果不存在,则需要决定在这种情况下该怎么做。

const metaObjects = [
  {
    id: 1,
    metaProp: "metaProp1"
  },
  {
    id: 2,
    metaProp: "metaProp2"
  }
];

const justObjects = [
  {
    id: 1,
    justProp: "justProp1"
  },
  {
    id: 2,
    justProp: "justProp2"
  }
];

justObjects.forEach(item => {
   let toMerge = metaObjects.find(obj => obj.id === item.id)
   Object.assign(toMerge, item)
})
console.log(metaObjects)

如果metaObjects可能很大,最好将其存储为键为id的对象。然后,您可以直接查找它,而不必每次都进行搜索。

如果您不想更改metaObject,可以在map()justObjects并创建一个新数组:

const metaObjects = [
  {
    id: 1,
    metaProp: "metaProp1"
  },
  {
    id: 2,
    metaProp: "metaProp2"
  }
];

const justObjects = [
  {
    id: 1,
    justProp: "justProp1"
  },
  {
    id: 2,
    justProp: "justProp2"
  }
];

let newArray = justObjects.map(item => {
   let toMerge = metaObjects.find(obj => obj.id === item.id)
   return Object.assign({}, toMerge, item)
})
// metaObjects unaffected 
console.log(newArray)

答案 2 :(得分:0)

我认为您可以将两个数组简单地组合在一起,按id将对象分组(您需要先排序),最后合并每个组:

const {
  map,
  mergeAll,
  groupWith,
  eqBy,
  prop,
  concat,
  sortBy,
  pipe
} = R;

const metaObjects = [
  { id: 1,
    metaProp: "metaProp1" },
  { id: 2,
    metaProp: "metaProp2" }];

const justObjects = [
  { id: 1,
    justProp: "justProp1" },
  { id: 2,
    justProp: "justProp2" }];

const process = pipe(
  concat,
  sortBy(prop('id')),
  groupWith(eqBy(prop('id'))),
  map(mergeAll));

console.log(

  process(metaObjects, justObjects)

);
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.min.js"></script>

答案 3 :(得分:0)

我将使用Array.prototype.reduce()for循环,使用{将其中一个从具有Array属性的对象id转换为对象对象, {1}}作为密钥:

id

或者:

const merged = metaObjects.reduce((acc, cur) => {
    acc[cur.id] = cur;

    return acc;
}, {});

然后,迭代另一个对象,同时将其每个条目合并到上面刚刚创建的对象中:

const merged = {};

for (const obj of metaObjects) {
    merged[obj.id] = obj;
}

最后,只需使用Object.values将其转换回justObjects.forEach((obj) => { merged[obj.id] = Object.assign({}, merged[obj.id], obj); });

Array

示例:

Object.values(merged);
const metaObjects = [{
  id: 1,
  metaProp: "metaProp1"
},{
  id: 2,
  metaProp: "metaProp2"
}];

const justObjects = [{
  id: 1,
  justProp: "justProp1"
},{
  id: 2,
  justProp: "justProp2"
},{
  id: 3,
  justProp: "justProp3"
}];

// Create an object of one of the two using is id property:

/*
// Alternative using reduce:

const merged = metaObjects.reduce((acc, cur) => {
  acc[cur.id] = cur;
  
  return acc;
}, {});
*/

// Alternative using a for loop:

const merged = {};

for (const obj of metaObjects) {
  merged[obj.id] = obj;
}

// Iterate the other one and merge it with the map you have just created:

justObjects.forEach((obj) => {
  merged[obj.id] = Object.assign({}, merged[obj.id], obj);
});

// Convert it back to an Array of objects:

console.log(Object.values(merged));

请注意,即使两个对象中的任何一个包含一个.as-console-wrapper { max-height: 100vh !important; }的条目,而在另一个对象中都不存在。