使用镜头合并两个对象的最简单方法

Simplest method to merge two objects using a Lens

我是 Ramda 的新手,我试图限制自己在调整时不使用 vanilla JS 方法来完成这样的任务。我被困在一些感觉很简单的事情上。当我需要像这样将一些东西链接在一起时,Ramda 对我来说就失去了清晰度。

我使用 R.groupBy 将一些其他数据聚合到一个带有一些键的对象中,我有一个目标对象,我想将其合并 - 但是来自 groupby 的键嵌套在其中。

我可以在目标 属性 上创建一个带有镜头的 view 来查看转换后的数据以匹配 - 我不太确定如何反向操作以将分组数据应用于嵌套对象。

let ungroupedData = [
  {"tag":"foo","id":99}, {"tag":"bar","id":33}, {"tag":"foo","id":14}, {"tag":"bar","id":26},
  {"tag":"baz","id":99}, {"tag":"qux","id":33}, {"tag":"foo","id":49}, {"tag":"bar","id":13}
];

let groupedData = R.map(R.pluck('id'), R.groupBy(R.prop('tag'),ungroupedData));

console.log({groupedData});
// groupedData:
// {
//   "foo": [99, 14, 49],
//   "bar": [33, 26, 13],
//   "baz": [99],
//   "qux": [33]
// }

let nestedTargetObjectToMerge = {
    "foo": { 
        //...
        "ids": [344, 121],
        //...
     },
     "bar": {
        //...
        "ids": [103, 66],
        //...
     }
}

// a view of the target object using a lens which matches groupedData
let view = R.map(R.view(R.lensProp("ids")), nestedTargetObjectToMerge);

console.log({view});
// view:
// {
//   "foo": [344, 121],
//   "bar": [103, 66]
// }

/* 
   let merged = ??
   // R.mergeDeepWithKey ?
   // R.over?
*/ 
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.min.js"></script>

预期结果

 {
     "foo" : {
       "ids" : [344, 121, 99, 14, 49],
     },
     "bar" : {
       "ids" : [103, 66, 33, 26, 13],
     },
     "baz" : { 
       "ids": [99],
     },
     "qux" : {
       "ids" : [33],
     }
 }

分组后,映射组,并使用 R.applySpecR.pluck 创建对象 ids。现在你可以使用 R.mergeDeepWithR.concat 结合两个对象上的 ids

const { pipe, groupBy, prop, map, applySpec, pluck, mergeDeepWith, concat } = R;

const groupData = pipe(
  groupBy(prop('tag')),
  map(applySpec({
    ids: pluck('id')
  }))
)

const ungroupedData = [{"tag":"foo","id":99},{"tag":"bar","id":33},{"tag":"foo","id":14},{"tag":"bar","id":26},{"tag":"baz","id":99},{"tag":"qux","id":33},{"tag":"foo","id":49},{"tag":"bar","id":13}];
const nestedTargetObjectToMerge = {"foo":{"ids":[344,121]},"bar":{"ids":[103,66]}};

const groupedData = groupData(ungroupedData);

const result = mergeDeepWith(
  concat,
  nestedTargetObjectToMerge, 
  groupedData
);

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

我的回答与 Ori Drori 的相似,但差异很大,因此也包括在内:

const extractIds = compose (map (objOf ('ids')), map (pluck ('id')), groupBy (prop ('tag')))

const group = compose (flip (mergeDeepWith (concat)), extractIds)

const nestedTargetObjectToMerge = {foo: {ids: [344, 121]}, bar: {ids: [103, 66]}}
const ungroupedData = [{tag: "foo", id: 99}, {tag: "bar", id: 33}, {tag: "foo", id: 14}, {tag: "bar", id: 26}, {tag: "baz", id: 99}, {tag: "qux", id: 33}, {tag: "foo", id: 49}, {tag: "bar", id: 13}]

console .log (
  group (ungroupedData) (nestedTargetObjectToMerge)
)
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.28.0/ramda.min.js"></script>
<script> const {compose, map, objOf, pluck, groupBy, prop, flip, mergeDeepWith, concat} = R </script>

此处 extractIds 将未分组的数据转换为与目标对象相同的格式,然后 group 使用它将其传递到 mergeDeepWith (concat)extreactId 可以很容易地内嵌到 group 中,但我发现这样更易读。


不过,我想评论一下:

I'm new to Ramda and trying to restrict myself to not resorting to vanilla JS methods for tasks like this while I adjust. I'm stuck on something that feels very simple. Ramda loses clarity for me as soon as I need to chain some things together like this.

我是 Ramda 的创始人和首席维护者之一。我是一个忠实粉丝。但我会非常警惕这种哲学。 Ramda 是一个工具;它旨在使以某种风格工作更容易。但它不应该为你接管一切。它通常可用于使您的代码更清晰。当它发生时使用它。如果没有,不要试图挤进去。如果这只是一个学习练习,那么当然可以使用 Ramda 解决方案。但为了你真正的工作,不要试图强迫它。

而且,虽然我对上面的解决方案以及 Ori Drori 的版本非常满意,但我不会打折使用单折叠的普通 JS 解决方案,如下所示:

const group = (xs) => (target) => 
  xs .reduce ((a, {tag, id}) => ({
    ...a, 
    [tag]: {...(a [tag] ?? {}), ids: [... (a [tag] ?.ids ?? []), id]}
  }), target)


const nestedTargetObjectToMerge = {foo: {ids: [344, 121]}, bar: {ids: [103, 66]}}
const ungroupedData = [{tag: "foo", id: 99}, {tag: "bar", id: 33}, {tag: "foo", id: 14}, {tag: "bar", id: 26}, {tag: "baz", id: 99}, {tag: "qux", id: 33}, {tag: "foo", id: 49}, {tag: "bar", id: 13}]

console .log (
  group (ungroupedData) (nestedTargetObjectToMerge)
)
.as-console-wrapper {max-height: 100% !important; top: 0}