gpt4 book ai didi

ramda.js - Ramda - 如何向嵌套对象添加新属性

转载 作者:行者123 更新时间:2023-12-02 16:04:55 27 4
gpt4 key购买 nike

我正在尝试向嵌套对象添加新属性 widthheight

我的数据结构是这样的:

const graph = {
id: 'root',
children: [
{
id: 'n1'
},
{
id: 'n2'
}
]
};

我正在尝试根据 id 为每个 child 添加独特的 widthheight 属性

我尝试了 R.lensPath。这里可以查看ramda editor :

const widthLens = R.curry((id, data) => R.lensPath([
'children',
R.findIndex(R.whereEq({ id }),
R.propOr([], 'children', data)),
'width',
]));

const setWidth = widthLens('n1', graph);
R.set(setWidth, '100', graph);

这几乎可以正常工作,但它只添加了 width 而且我需要遍历所有子对象并返回具有新属性的相同对象。它看起来也过于复杂,因此非常欢迎任何建议。谢谢。

最佳答案

有几种不同的方法可以解决这个问题。但一种可能性是使用自定义镜头类型。 (这与 Ori Drori 的优秀答案完全不同,后者仅使用 Ramda 的 lensPath。)

Ramda(免责声明:我是作者之一)仅提供几种特定类型的镜头——一种用于简单属性,另一种用于数组索引,第三种用于更复杂的对象路径。但它允许您构建您可能需要的那些。并且镜头不仅仅针对简单的对象/阵列属性而设计。将它们视为您的某些数据集的框架,您可以专注于此。

因此我们可以编写一个 lens 来关注具有特定 id 的数组元素。我们需要就如何处理丢失的 ID 做出决定。我将在此处选择——如果未找到 id——为 get 返回 undefined 并附加到 set 的末尾>,但也有一些合理的替代方案可供探索。

在实现方面,id 没有什么特别之处,所以我将基于一个特定的命名属性来实现,并在一个单独的函数中将其专门化为 id。我们可以这样写:

const lensMatch = (propName) => (key) => lens ( 
find (propEq (propName, key)),
(val, arr, idx = findIndex (propEq (propName, key), arr)) =>
update(idx > -1 ? idx : length (arr), val, arr)
)

const lensId = lensMatch ('id')

它会像这样工作:

const lens42 = lensId (42)

const a = [{id: 17, x: 'a'}, {id: 42, x: 'b'}, {id: 99, x: 'c'}, {id: 57, x: 'd'}]

view (lens42, a) //=> {id: 42, x: 'b'}
set (lens42, {id: 42, x: 'z', foo: 'bar'}, a)
//=> [{id: 17, x: 'a'}, {id: 42, x: 'z', foo: 'bar'}, {id: 99, x: 'c'}, {id: 57, x: 'd'}]
over (lens42, assoc ('foo', 'qux'), a)
//=> [{id: 17, x: 'a'}, {id: 42, x: 'b', foo: 'qux'}, {id: 99, x: 'c'}, {id: 57, x: 'd'}]

但是接下来我们需要处理我们的 widthheight 属性。一种非常有用的方法是关注具有给定特定属性的对象,以便我们得到类似{width: 100, height: 200}的东西,我们将这样的对象传递到 set 中。事实证明写起来很优雅:

const lensProps = (props) => lens (pick (props), mergeLeft)

我们会像这样使用它:

const bdLens = lensProps (['b', 'd'])

const o = ({a: 1, b: 2, c: 3, d: 4, e: 5})
view (bdLens, o) //=> {b: 2, d: 4}
set (bdLens, {b: 42, d: 99}, o) //=> {a: 1, b: 42, c: 3, d: 99, e: 5}
over (bdLens, map (n => 10 * n), o) //=> {a: 1, b: 20, c: 3, d: 40, e : 5}

结合这些,我们可以开发一个像这样使用的函数:setDimensions('n1', {width: 100, height: 200}, graph) 我们首先写一个镜头来处理id和我们的维度:

const lensDimensions = (id) => compose (
lensProp ('children'),
lensId (id),
lensProps (['width', 'height'])
)

然后我们调用这个镜头的setter via

const setDimensions = (id, dimensions, o) => 
set (lensDimensions (id), dimensions, o)

我们可以把这些放在一起

const lensMatch = (propName) => (key) => lens ( 
find (propEq (propName, key)),
(val, arr, idx = findIndex (propEq (propName, key), arr)) =>
update(idx > -1 ? idx : length (arr), val, arr)
)
const lensProps = (props) => lens (pick (props), mergeLeft)

const lensId = lensMatch ('id')

const lensDimensions = (id) => compose (
lensProp ('children'),
lensId (id),
lensProps (['width', 'height'])
)

const setDimensions = (id, dimensions, o) => set (lensDimensions (id), dimensions, o)

const graph = {id: 'root', children: [{id: 'n1'}, {id: 'n2'}]}

console .log (setDimensions ('n1', {width: 100, height: 200}, graph))
//=> {id: "root", children: [{ id: "n1", height: 200, width: 100}, {id: "n2"}]}
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.27.1/ramda.min.js"></script>
<script> const {find, propEq, findIndex, update, length, lens, pick, mergeLeft, compose, lensProp, set} = R </script>

这显然涉及比 Ori Drori 的答案更多的代码行。但它创建了有用的、可重复使用的镜头创建器、lensMatchlensIdlensProps

注意:如果我们尝试使用未知 ID,这将失败。我有一个修复程序,但我现在没有时间深入研究它失败的原因,可能与镜头构成的方式有点不直观有关。如果我很快找到时间,我会重新研究它。但目前,我们可以简单地将 lensProps 更改为

const lensProps = (props) => lens (compose (pick (props), defaultTo ({})), mergeLeft)

然后一个未知的 id 将附加到末尾:

console .log (setDimensions ('n3', {width: 100, height: 200}, graph))
//=> {id: "root", children: [{id: "n1"}, {id: "n2"}, {id: "n3", width : 100, height : 200}]}

关于ramda.js - Ramda - 如何向嵌套对象添加新属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69696791/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com