首页 > 解决方案 > 使用 ramda 组合镜头

问题描述

我正在尝试查询嵌套对象的内容coor

const data = [ 
   [ [{geo: {coor: [1,2]}}, {geo: {coor: [4,5]}}], {} ], 
   [ [{geo: {coor: [8,2]}}, {geo: {coor: [9,5]}}], {} ]
 ]

结果应该是:

[[[1, 2], [4, 5]], [[8, 2], [9, 5]]]

我使用以下代码来获得此结果:

const viewLens = R.view(R.lensPath(['geo', 'coor']))
R.map(R.map(viewLens), R.map(R.view(lensIndex(0)), data))

但我想组成一个可以用来映射的镜头data,类似于:

const coorLens = R.compose(R.lensIndex(0), ..., R.lensPath(['geo', 'coor']))

可以像这样使用:

R.map(coorLens, data)

有人知道如何制作这样的镜头吗?

谢谢!

标签: ramda.jslenses

解决方案


有一个mappedsetter 的概念,可用于更新镜头构造中函子上的值,尽管这只能与over/一起使用set而不能view(即如何从只能由 修改的东西中获取元素map?)

还有一种可遍历光学的概念,它可以专注于许多元素而不仅仅是一个元素。这使您既可以更新焦点下的所有元素,又可以说明您希望如何将多个元素组合在一个结果中,您还可以查看它们。但是,这不会为您提供完全相同的结构,因为与示例中的列表列表不同,所有焦点元素都将组合在一起。

Ramda 本身不提供此功能,但可以在ramda-lens库中找到它。

const RL = ramdaLens

const data = [ 
  [ [{geo: {coor: [1,2]}}, {geo: {coor: [4,5]}}], {} ], 
  [ [{geo: {coor: [8,2]}}, {geo: {coor: [9,5]}}], {} ]
]

const coorLens = R.compose(
  RL.traversed,
  R.lensIndex(0),
  RL.traversed,
  R.lensPath(['geo', 'coor'])
)

console.log(
  "Combine all the focused elements in a list\n",
  RL.listOf(coorLens, data)
)

console.log(
  "Update all the focused elements\n",
  RL.over(coorLens, R.map(R.inc), data)
)
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.min.js"></script>
<script src="https://wzrd.in/standalone/ramda-lens"></script>

我觉得值得指出的是,除非您在这里通过组合镜头的能力获得任何东西,或者查看和更新​​聚焦元素,否则可能更简单地避免镜头具有可以说是更简单的功能组合,如下所示。

const data = [ 
  [ [{geo: {coor: [1,2]}}, {geo: {coor: [4,5]}}], {} ], 
  [ [{geo: {coor: [8,2]}}, {geo: {coor: [9,5]}}], {} ]
]

const fn = R.map(R.pipe(R.head, R.map(R.path(['geo', 'coor']))))

console.log(
  "Without lenses\n",
  fn(data)
)
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.min.js"></script>


推荐阅读