[英]Update object value Ramda
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 .
但現在我有一個新問題。 例如,我想用 id 12 更新 object 中的標題。
我的數據 model:
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)
您可以在此處使用鏡頭:
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 的 object,無論它屬於哪個組。然后我編寫myLens
來接受一個 id 和一個屬性名稱,並返回一個專注於該屬性的鏡頭object。
有了這些,我們可以使用 Ramda 的view
、 set
和over
來查看值、設置值或使用 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) => 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>
請注意,只有當該 id 實際存在時, set
和over
才會起作用。 您可能需要先使用view
進行檢查。
myLens
很簡單; 這就是鏡頭構圖的工作原理。 (請注意,它似乎從常規撰寫中倒流; 技術原因很有趣,但超出了 SO 答案的 scope。)但idInObjLens
更復雜。 與所有鏡頭一樣,它需要一個 getter 和一個 setter。 他們兩個同時找到 object 鍵,該鍵包含與該 object 鍵關聯的數組中具有該鍵的 id 和索引的項目。 getter 只是簡單地返回值。 setter 使用assoc
更新外部 object 並update
以更新其中的數組。 所有其他嵌套對象都通過引用簡單地返回。
這不是值得驕傲的代碼。 它有效,當然這是主要的。 但我真的不喜歡將數組索引計算為find
調用的副作用。 然而,再次計算它似乎有點過分了。 我也不太喜歡idInObjLens
這個名字,而且我總是覺得如果我沒有一個好名字,我就會錯過一些基本的東西。 (我對myLens
沒有同樣的反對意見,因為我認為你會為你的用例有一個更好的名字。)
這與 Hitmand 的解決方案之間的最大區別在於,該鏡頭不需要您預先知道外部 object 中的哪個鍵持有您的 ID 項目。 這給解決方案增加了相當多的復雜性,但使其 API 更加靈活。
您 map 屬性內的所有數組,並使用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>
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.