如何使用 Ramda 将对象映射转换为数组?

hax*_*nel 3 javascript functional-programming ramda.js

我想从以下对象进行转换:

{
  'id-1': { prop: 'val1' },
  'id-2': { prop: 'val2' },
}
Run Code Online (Sandbox Code Playgroud)

至数组:

[
  { id: 'id-1', prop: 'val1' },
  { id: 'id-2', prop: 'val2' },
]
Run Code Online (Sandbox Code Playgroud)

到目前为止我所做的(有效):

R.pipe(
  R.toPairs,
  R.map(([id, props]) => ({
    id,
    ...props,
  }))
)
Run Code Online (Sandbox Code Playgroud)

如果可能的话,我想仅使用 Ramda 来解决它。

Sco*_*yet 6

我建议“仅使用 Ramda”解决它是一个糟糕的设计目标,除非这是学习 Ramda 的练习。我是 Ramda 的创始人之一,也是它的忠实粉丝,但 Ramda 只是一个旨在简化代码的工具包,以便更轻松地在特定范例中工作。

也就是说,我们当然可以使用 Ramda 编写一个无点版本。我首先想到的是这个*

const transform = pipe(
  toPairs,
  map(apply(useWith(merge, [objOf('id'), identity])))
)

const data = {'id-1': { prop: 'val1' }, 'id-2': { prop: 'val2'}}

console.log(transform(data))
Run Code Online (Sandbox Code Playgroud)
<script src="https://bundle.run/ramda@0.26.1"></script><script>
const {pipe, toPairs, map, apply, useWith, merge, objOf, identity} = ramda    </script>
Run Code Online (Sandbox Code Playgroud)

但这比你原来的可读性更差,而不是更多。

这段代码:

const transform = pipe(
  toPairs,
  map(([id, props]) => ({...props, id}))
)
Run Code Online (Sandbox Code Playgroud)

是非常清晰的,而 Ramda 版本需要人们理解 Ramda 特定的useWith并且objOf稍微晦涩apply——我希望mapmerge、 和identity是清楚的。

事实上,这段代码非常简单,我可以将其编写为一行代码,在这种情况下,我切换到composeover pipe

const transform = compose(map(([id, props]) => ({...props, id})), toPairs)
Run Code Online (Sandbox Code Playgroud)

但我可能不会这样做,因为我发现多行pipe版本更容易阅读。

最后请注意,我们可以以一种相当易读的方式完成此操作,而无需任何 Ramda 工具:

const transform = (data) => 
  Object.entries(data).map(
    ([id, props]) => ({...props, id})
  )
Run Code Online (Sandbox Code Playgroud)

如果我已经在我的代码库中使用 Ramda,我会更喜欢pipe上面的版本;我认为它更容易阅读。但绝不会仅仅因为这个相当小的差异就将 Ramda 引入到项目中。

我担心人们对无点代码产生迷恋。这是一个工具。当它使您的代码更容易理解时使用它。当它使您的代码变得更加晦涩时,请跳过它。在这里,我认为您是从非常可读的代码开始的;很难对其进行改进。


*注意这里identity并不是绝对必要的;你可以跳过它,不会有什么坏处。useWith没有它生成的函数identity将错误地报告 arity 1,但由于该函数立即被 包装apply,然后进一步放置在从 接收二元素数组的上下文中toPairs,所以没有任何东西依赖于该 arity。但我发现无论如何都包含它是一个好习惯。