admin 管理员组文章数量: 1086019
In previous question I tried to group arrays by parent ids and then remove them from each object - Group arrays by parent ids object Ramda.
But now I have a new issue. For example I want to update title in object with id 12.
My data model:
const stuff = {
"31": [
{
"id": "11",
"title": "ramda heeeelp"
},
{
"id": "12",
"title": "ramda 123"
}
],
"33": [
{
"id": "3",
"title": "..."
}
],
"4321": [
{
"id": "1",
"title": "hello world"
}
]
}
Attempts:
const alter = (id, key, value) => pipe(
values,
flatten,
update(...) // <= end of my attempts
// then group again
)
alter('12', 'title', 'new heading 123')(stuff)
In previous question I tried to group arrays by parent ids and then remove them from each object - Group arrays by parent ids object Ramda.
But now I have a new issue. For example I want to update title in object with id 12.
My data model:
const stuff = {
"31": [
{
"id": "11",
"title": "ramda heeeelp"
},
{
"id": "12",
"title": "ramda 123"
}
],
"33": [
{
"id": "3",
"title": "..."
}
],
"4321": [
{
"id": "1",
"title": "hello world"
}
]
}
Attempts:
const alter = (id, key, value) => pipe(
values,
flatten,
update(...) // <= end of my attempts
// then group again
)
alter('12', 'title', 'new heading 123')(stuff)
Share
Improve this question
asked Nov 4, 2019 at 12:31
ArthurArthur
3,5267 gold badges36 silver badges66 bronze badges
1
-
2
Ramda is designed with immutable data in mind. Can't you just use
assocPath(['12', 'title'], 'new heading 123')
to get a copy of the object with the value replaced with a new one? – Jonas Høgh Commented Nov 4, 2019 at 13:03
3 Answers
Reset to default 3You can use lenses here:
- Over: https://ramdajs./docs/#over
- Set: https://ramdajs./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./ajax/libs/ramda/0.26.1/ramda.js" integrity="sha256-xB25ljGZ7K2VXnq087unEnoVhvTosWWtqXB4tAtZmHU=" crossorigin="anonymous"></script>
I think this would be best done with a custom lens
. Here I write a lens creator (idInObjLens
) that focuses on the object with the correct id, regardless of what group it falls in. Then I write myLens
to accept an id and a property name and return you a lens that focuses on that property of the object.
With those, we can use Ramda's view
, set
, and over
to see the value, set the value, or update the value with a function:
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) => pose (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./ajax/libs/ramda/0.26.1/ramda.js"></script>
<script>const {lens, find, findIndex, propEq, values, toPairs, assoc, update, pose, lensProp, view, set, over, toUpper } = R</script>
Note that the set
and over
will only work if that id actually exists. You might want to check using view
first.
myLens
is simple; it's just how lens position works. (Notice that it seems to flow backward from regular pose; the technical reasons are interesting, but beyond the scope of an SO answer.) But idInObjLens
is more plex. 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
to update the array inside it. All other nested objects are simply returned by reference.
This is not code to be proud of. It works, and of course that's the main thing. But I really don't like calculating the array index as a side-effect of the find
call. Yet calculating it a second time just seems overkill. I also don't really like the name idInObjLens
and I always feel that if I don't have a good name, I'm missing something fundamental. (I don't have the same objection to myLens
, as I assume you will have a better name for this for your use-case.)
The big difference between this and the solution from Hitmand is that this lens does not require you to know up-front which key in the outer object holds the item with your id. That adds a fair bit of plexity to the solution, but makes its API much more flexible.
You map all array inside properties, and use R.when
to evolve all objects with matching id
s, and replace the property's (title
in your case) value:
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./ajax/libs/ramda/0.26.1/ramda.js" integrity="sha256-xB25ljGZ7K2VXnq087unEnoVhvTosWWtqXB4tAtZmHU=" crossorigin="anonymous"></script>
本文标签: javascriptUpdate object value RamdaStack Overflow
版权声明:本文标题:javascript - Update object value Ramda - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://roclinux.cn/p/1744084632a2530891.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论