本文介绍了Ramda js:具有嵌套对象数组的深层嵌套对象的镜头的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

使用Ramda.js(和镜头),我想修改下面的JavaScript对象,将NAME:VERSION1更改为NAME:VERSION2,以获取ID =/ 1 / B / i的对象。 / p>

我想使用镜头,因为我想改变一个深度嵌套的值,但是保持整个结构不变。



我不想使用lensIndex,因为我永远不知道数组的顺序,所以相反,我想通过查找它的id字段来查找数组中的对象。



我可以用镜头做,或者我应该用不同的方式吗?

  {
id:/ 1,
groups:[
{
id:/ 1 / A,
apps:[
{
id:/ 1 / A / i,
跳过更多嵌套数据以简化示例:{}
}
$
},
{
id:/ 1 / B,
apps:[
{id:/ 1 / B / n,container:{}},
{
id: / 1 / B / i,

容器:{
docker:{
image:NAME:VERSION1,
otherStuff:{}
}
}
}
]
}

]
}


解决方案

这应该可以通过创建一个与ID对象匹配的镜头来实现与其他镜头组合以向下钻取到图像区域。



首先,我们可以创建一个镜头,专注于与某些谓词匹配的数组元素(注意:如果保证匹配列表中至少一个元素,这只是一个有效的镜头)

  // ::(a  - >布尔) - >镜头[a] a 
const lensMatching = pred => (toF => entities => {
const index = R.findIndex(pred,entities);
返回R.map(entity => R.update(index,entity,entities),
toF(entities [index]));
});

请注意,我们在这里手动构建镜头而不是使用 R.镜头保存重复查找与谓词匹配的项目的索引。



一旦我们有了这个功能,我们就可以构建一个匹配的镜头给定的ID。

  // :: String  - >镜头[{id:String}] {id:String} 
const lensById = R.compose(lensMatching,R.propEq('id'))

然后我们可以将所有镜头组合在一起以定位图像区域

  const imageLens = R.compose(
R.lensProp('groups'),
lensById('/ 1 / B'),
R.lensProp('apps'),
lensById('/ 1 / B / i'),
R.lensPath(['container','docker','image'])

可以用来更新数据对象,如下所示:

  set(imageLens,'NAME:VERSION2',data)

如果您想要并声明一个专注于图像字符串版本的镜头,您可以更进一步。

  const vLens = R.lens(
R.compose(R.nth(1),R.split(':')),
(版本, str)=> R.replace(/:。* /,':'+ version,str)


set(vLens,'v2','NAME :v1')//'NAME:v2'

然后可以将其附加到 imageLens 定位整个对象中的版本。

  const verLens = compose (imageLens,vLens); 
set(verLens,'VERSION2',数据);


Using Ramda.js (and lenses), I want to modify the JavaScript object below to change "NAME:VERSION1" to "NAME:VERSION2" for the object that has ID= "/1/B/i".

I want to use a lens because I want to just change one deeply nested value, but otherwise retain the entire structure unchanged.

I don't want to use lensIndex because I never know what order the arrays will be in, so instead, I want to "find" the object in an array by looking for its "id" fields.

Can I do this with lenses, or should I do it a different way?

{
  "id": "/1",
  "groups": [
    {
      "id": "/1/A",
      "apps": [
        {
          "id": "/1/A/i",
          "more nested data skipped to simplify the example": {}
        }
      ]
    },
    {
      "id": "/1/B",
      "apps": [
        { "id": "/1/B/n", "container": {} },
        {
          "id": "/1/B/i",

          "container": {
            "docker": {
              "image": "NAME:VERSION1",
              "otherStuff": {}
            }
          }
        }
      ]
    }

  ]
}
解决方案

This should be possible by creating a lens that matches an object by ID which can then be composed with other lenses to drill down to the image field.

To start with, we can create a lens that will focus on an element of an array that matches some predicate (note: this will only be a valid lens if it is guaranteed to match at least one element of the list)

//:: (a -> Boolean) -> Lens [a] a
const lensMatching = pred => (toF => entities => {
    const index = R.findIndex(pred, entities);
    return R.map(entity => R.update(index, entity, entities),
                 toF(entities[index]));
});

Note that we're manually constructing the lens here rather than using R.lens to save duplication of finding the index of the item that matches the predicate.

Once we have this function we can construct a lens that matches a given ID.

//:: String -> Lens [{ id: String }] { id: String }
const lensById = R.compose(lensMatching, R.propEq('id'))

And then we can compose all the lenses together to target the image field

const imageLens = R.compose(
  R.lensProp('groups'),
  lensById('/1/B'),
  R.lensProp('apps'),
  lensById('/1/B/i'),
  R.lensPath(['container', 'docker', 'image'])
)

Which can be used to update the data object like so:

set(imageLens, 'NAME:VERSION2', data)

You could then take this a step further if you wanted to and declare a lens that focuses on the version of the image string.

const vLens = R.lens(
  R.compose(R.nth(1), R.split(':')),
  (version, str) => R.replace(/:.*/, ':' + version, str)
)

set(vLens, 'v2', 'NAME:v1') // 'NAME:v2'

This could then be appended to the composition of imageLens to target the version within the entire object.

const verLens = compose(imageLens, vLens);
set(verLens, 'VERSION2', data);

这篇关于Ramda js:具有嵌套对象数组的深层嵌套对象的镜头的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-16 14:05
查看更多