更新 object 值 Ramda

Update object value Ramda

在上一个问题中,我尝试按 parent id 对数组进行分组,然后从每个 object - .

中删除它们

但是现在我有一个新问题。例如,我想用 id 12 更新 object 中的标题。

我的数据模型:

const stuff = {
  "31": [
    {
      "id": "11",
      "title": "ramda heeeelp"
    },
    {
      "id": "12",
      "title": "ramda 123"
    }
  ],
  "33": [
    {
      "id": "3",
      "title": "..."
    }
  ],
  "4321": [
    {
      "id": "1",
      "title": "hello world"
    }
  ]
}

尝试次数:

const alter = (id, key, value) => pipe(
  values,
  flatten,
  update(...) // <= end of my attempts
  // then group again
)

alter('12', 'title', 'new heading 123')(stuff)

您可以在此处使用 lenses

  1. 超过:https://ramdajs.com/docs/#over
  2. 设置:https://ramdajs.com/docs/#set

const titleLens = R.curry((key, id, data) => R.lensPath([
  key, 
  R.findIndex(R.whereEq({ id }), R.propOr([], key, data)), 
  'title'
]));

// ----
const stuff = {
  "31": [
    {
      "id": "11",
      "title": "ramda heeeelp"
    },
    {
      "id": "12",
      "title": "ramda 123"
    }
  ],
  "33": [
    {
      "id": "3",
      "title": "..."
    }
  ],
  "4321": [
    {
      "id": "1",
      "title": "hello world"
    }
  ]
}

const title3111 = titleLens('31', '11', stuff);
const result = R.set(title3111, 'DID RAMDA HELP YOU?', stuff);

console.log('result', result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js" integrity="sha256-xB25ljGZ7K2VXnq087unEnoVhvTosWWtqXB4tAtZmHU=" crossorigin="anonymous"></script>

我认为这最好通过自定义 lens 来完成。在这里,我编写了一个镜头创建器 (idInObjLens),它专注于具有正确 id 的对象,而不管它属于哪个组。然后我编写 myLens 来接受一个 id 和一个 属性 name 和 return 你一个镜头,聚焦在物体的 属性 上。

有了这些,我们可以使用 Ramda 的 view, set, and over 来查看值、设置值或使用函数更新值:

const idInObjLens = (id) => lens (
  (obj) => {
    let index = -1
    const child = find (value => (index = findIndex (propEq ('id', id), value)) > -1, values (obj) )
    if (child) return child [index]
  },
  (val, obj) => {
    let index = -1
    const [key, value] = find (([key, value]) => (index = findIndex (propEq ('id', id), value)) > -1, toPairs (obj) )
    return assoc (key, update (index, val, value), obj)
  },
)


const myLens = (id, key) => compose (idInObjLens (id), lensProp (key))

const stuff = {"31": [{"id": "11", "title": "ramda heeeelp"},  {"id": "12", "title": "ramda 123"}], "33": [{"id": "3", "title": "..."}], "4321": [{"id": "1", "title": "hello world"}]};

[
    view (myLens ('12', 'title'), stuff),
    set  (myLens ('3',  'title'), 'new heading 123', stuff),
    over (myLens ('1',  'title'), toUpper, stuff),
] .forEach (x => console .log (x))
.as-console {background-color:black !important; color:lime;}
.as-console-wrapper {max-height:100% !important; top:0;}
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script>
<script>const {lens, find, findIndex, propEq, values, toPairs, assoc, update, compose, lensProp, view, set, over, toUpper } = R</script>

请注意,setover 仅在该 ID 实际存在时才有效。您可能想先使用 view 进行检查。

myLens很简单;这就是镜头构图的工作原理。 (请注意,它似乎从常规组合向后流动;technical reasons are interesting, but beyond the scope of an SO answer.) But idInObjLens is more complex. As with all lenses, it takes a getter and a setter. Both of them simultaneously find the object key that contains the item with the id and the index of that key in the array associated with that object key. The getter simply returns the value. The setter uses assoc to update the outer object and update 更新其中的数组。所有其他嵌套对象只是通过引用 returned。

这不是值得骄傲的代码。它有效,当然这是最主要的。但我真的不喜欢将数组索引计算为 find 调用的副作用。然而,第二次计算它似乎有点过分了。我也不太喜欢 idInObjLens 这个名字,我总觉得如果我没有一个好名字,我就会失去一些基本的东西。 (我对 myLens 没有同样的反对意见,因为我认为您的用例会有更好的名称。)

这与 Hitmand 的解决方案之间的最大区别在于,此镜头不需要您预先知道外部对象中的哪个键持有具有您的 ID 的项目。这给解决方案增加了相当多的复杂性,但使其 API 更加灵活。

您将所有数组映射到属性中,并使用 R.when 进化所有具有匹配 id 的对象,并替换 属性 的(title 在您的案例)值:

const { curry, map, when, propEq, evolve, always } = R

const fn = curry((id, prop, content) =>
  map(map( // map all objects of all properties
    when(
      propEq('id', id),  // if the id of an object matches
      evolve({ [prop]: always(content) })) // evolve it's property to the content
    )
  ))

const data = {"31":[{"id":"11","title":"ramda heeeelp"},{"id":"12","title":"ramda 123"}],"33":[{"id":"3","title":"..."}],"4321":[{"id":"1","title":"hello world"}]}

const result = fn('12', 'title', 'new heading 123')(data)

console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js" integrity="sha256-xB25ljGZ7K2VXnq087unEnoVhvTosWWtqXB4tAtZmHU=" crossorigin="anonymous"></script>