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



我是Ramda的新手,并试图限制自己在调整时不诉诸于这样的任务的香草JS方法。我被一些感觉很简单的东西困住了。当我需要像这样把一些事情串在一起时,Ramda对我来说就不清晰了。

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

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

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 droori的相似,但又有足够的不同,因此也包含了它:

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,但我发现这样更容易读。


然而,我想评论一下:

我是Ramda的新手,并试图限制自己在调整时不诉诸于这样的任务的香草JS方法。我被一些感觉很简单的东西困住了。当我需要像这样把一些事情串在一起时,Ramda对我来说就不清晰了。

我是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}

最新更新