用另一个 object 的详细信息填充 object

Populate object with detail from another object

我有两个项目:

列表:

[{
  "key": "A",
  ...optionalAprops
}, {
  "key": "C",
  ...optionalCProps
}]

Collection:

{
  "A": {
    ...detailAprops
  },
  "B": {
    ...detailBprops
  },
  "C": {
    ...detailCprops
  }
}

如何使用 Ramda.js 或函数式样式,使用 Collection 中的详细信息填充 List,已映射通过它的? 结果应该像

[{
  "key": "A",
  ...optionalAprops,
  ...detailAprops
}, {
  "key": "C",
  ...optionalCprops,
  ...detailCprops
}]

我现在拥有的是

var populate = R.curry(function(coll, item) {
  return R.merge(item, R.props(R.props('key', item), coll));
});

var result = R.map(populate(Collection))(List);

populate 函数在我看来非常 un-functional,因为它仍然传递状态。有没有更简洁的方法来完成相同的任务,使用 Ramda.js? 步骤细分为

我认为将状态保持在您想要的位置的最简单方法是将 map 调用移动到您的函数中:

var populate = R.curry(function(coll, list) {
  return R.map(function(item) {
    return R.merge(item, R.prop(R.prop('key', item), coll))
  }, list);
});

populate(Collection, List); 
// or `populate(Collection)` to create a function that accepts a List

(请注意,我将 R.props 替换为 R.prop。我认为这只是一个打字错误;否则您会包含各种可能不需要的键。)

可能有一些方法可以让这个免分,但它最终可能会变得更丑陋。也许不是;我没试过。但我认为无积分只有在它使代码更具可读性时才有用。我怀疑它会在这里。

另请注意 ES6 箭头函数在多大程度上有助于清理此问题:

var populate = R.curry((coll, list) => R.map(
  item => R.merge(item, R.prop(R.prop('key', item), coll)
), list));

您可以在 Ramda REPL

中看到所有这些

更新

我确实想看看这在无积分风格下会是什么样子。正如我所怀疑的那样,这远不如原始解决方案那么干净,远不如 ES6 版本,但也没有我担心的那么糟糕:

var populate = R.curry(R.useWith(
  R.map, 
  R.flip(R.converge(
    R.merge, 
    R.identity, 
    R.useWith(R.prop, R.prop('key'))
  )), 
  R.identity
));

注意大量使用 Ramda 的两个古怪函数,useWith and converge。这些是功能组合的替代样式,通常非常有用。

你可以在 REPL.

中看到我如何将一个转换为另一个的步骤