如何使用 ramda 表达式编辑数组中的对象?
How to edit an object inside array using ramda expressions?
我有一个这样的数组:
[
{
id: '1852',
label: 'One',
types: [1, 2, 4]
},
{
id: '1854852',
label: 'Two',
types: [1, 2]
},
{
id: '4581852',
label: 'Three',
types: [1]
}
]
id属性是唯一的,我用它来获取对象
我有一个对象的变化(例如第三个),我希望它是这样的:
{
id: '4581852',
label: 'new Three',
types: [1, 7, 9]
}
如何对数组进行适当的更改?
因为现在我在做一个不好的解决方案,我试图通过它的id找到元素,从数组中删除它,然后将新对象推入数组,但它总是在最后当然,这不适合我。
如有任何帮助,我们将不胜感激。
您可以使用Array#find
获取对象,然后直接更新其属性。
const arr = [
{
id: '1852',
label: 'One',
types: [1, 2, 4]
},
{
id: '1854852',
label: 'Two',
types: [1, 2]
},
{
id: '4581852',
label: 'Three',
types: [1]
}
]
const obj = arr.find(({id})=>id==='4581852');
obj.label = 'new Three';
obj.types.push(7,9);
console.log(arr);
您可以在 list
中查找 id
并将 object
替换为您找到的内容。
请记住,这种方式 object
必须包含所有属性。
const replace = (list, id, object) => {
const index = list.findIndex(item => item.id === id);
return [...list.slice(0, index), object, ...list.slice(index + 1)]
}
替换 2nd 元素的示例用法:
const list = [
{
id: '1852',
label: 'One',
types: [1, 2, 4]
},
{
id: '1854852',
label: 'Two',
types: [1, 2]
},
{
id: '4581852',
label: 'Three',
types: [1]
}
]
const nextList = replace(list, "1854852", { id: "1854852", label: 'Other Three', types: [1, 2, 3] })
首先,Ramda 不会 帮助您编辑您的值,如果“编辑”是指就地更改。 Ramda(免责声明:我是作者之一)非常注重处理不可变数据。然而,它有许多技术可以帮助您创建数据的更改副本。不过,我不确定它们是否值得,因为相当简单的 ES6 版本也一样干净。
如果您确实想使用 Ramda,一个版本可能如下所示:
const updateAt = (id, transform) =>
map (when (propEq ('id', id), transform))
const data = [{id: '1852', label: 'One', types: [1, 2, 4]}, {id: '1854852', label: 'Two', types: [1, 2]}, {id: '4581852', label: 'Three', types: [1]}]
console.log ( 'Setting the value',
updateAt ('4581852', assoc ('label', 'new Three')) (data)
)
console .log ( 'Updating the value',
updateAt ('1852', evolve ({'label': concat('new ')})) (data)
)
console .log ( 'Original data unchanged', data)
.as-console-wrapper {min-height: 100% !important; top: 0}
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.27.0/ramda.js"></script>
<script> const {map, when, propEq, assoc, evolve, concat} = R </script>
我们展示了两种不同的调用方式:一种是我们将 label
属性 与您的新值相关联。在第二个中,我们通过将 'new '
和当前值连接在一起来改进您的对象。
如果我们愿意,我们可以写一个无积分版本。 Ramda 从早期开始就包含了使之成为可能的工具,尽管它们至少在某种程度上不受核心团队的青睐。其中之一是useWith
,我们可以用它来写这个函数
const updateAt = compose (map, useWith (when, [propEq ('id')]))
不过,我不推荐这样做。初始版本似乎很容易阅读和理解。这个版本更紧凑,但似乎并没有真正从最初的版本中获得任何其他东西,而且可以说更难理解。
第二种可能是使用镜头。 (有几个很好的介绍,包括来自 Richard Tan.) Lenses allow you to focus on a particular part of a data structure, in order to view the value, set it directly, or alter it with a function. Ramda provides these general-purpose functions in view
, set
, and over
. It also has a few function to build lenses, such as lensProp
, lensIndex
, and lensPath
. But we are free to use lens
的一个,用于构建我们自己的,传递 getter 和 setter 函数。
因此我们可以编写一个镜头来查找列表中与特定 属性 匹配的值,并使用它来构建我们的函数。它可能看起来像这样:
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 idLens = lensMatch('id')
const setLabelById = (id, val) =>
set(compose(idLens(id), lensProp('label')), val)
const updateLabelById = (id, fn) =>
over(compose(idLens(id), lensProp('label')), fn)
const data = [{id: '1852', label: 'One', types: [1, 2, 4]}, {id: '1854852', label: 'Two', types: [1, 2]}, {id: '4581852', label: 'Three', types: [1]}]
console .log ( 'Setting the value',
setLabelById ('4581852', 'new Three') (data)
)
console .log ( 'Updating the value',
updateLabelById('4581852', concat('new '))(data)
)
.as-console-wrapper {min-height: 100% !important; top: 0}
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.27.0/ramda.js"></script>
<script> const {lens, find, propEq, findIndex, update, length, over, compose, lensProp, set, concat} = R </script>
同样,我们编写了两个不同版本的函数,具体取决于您是只想设置值还是用函数更新它。
这比原来的版本多了很多代码,所以有人可能会问有什么好处。答案很简单:我们在这里得到两个非常有用的可重用函数:lensMatch
和 idLens
。 lensMatch
让我们定义一个 属性 来检查并关注与 属性 上的给定值匹配的(第一个)元素。 idLens
专门用于 属性 id
。它们有更多的潜在用途并且非常有价值,Ramda 团队真的应该考虑包括它们。 (自我注释...)
稍微想一想,我们可能会想出更多的 Ramda 函数组合来帮助解决这个问题。但我怀疑这是否真的值得,因为你的具体问题可以用一个足够简单的 ES6 函数来解决,根本不用 Ramda。
const setLabelById = (id, val, data, index = data.findIndex(({id: i}) => id == i)) =>
index < 0
? data
: [...data.slice(0, index), {...data[index], label: val}, ...data.slice(index + 1)]
const data = [{id: '1852', label: 'One', types: [1, 2, 4]}, {id: '1854852', label: 'Two', types: [1, 2]}, {id: '4581852', label: 'Three', types: [1]}]
console .log (
setLabelById ('4581852', 'new Three', data)
)
.as-console-wrapper {min-height: 100% !important; top: 0}
我们可以用同样的方式轻松编写一个 updateLabelById
函数。
这项技术与 Dave 的回答有相当多的重叠,但它是从旧条目构建新条目,仅替换 label
属性.
我会非常警惕“使用 Ramda 表达式”这个短语。 Ramda 是一种旨在使以某种风格编写代码更容易的工具。它不是一个框架。除非你将编写代码作为练习来学习更多关于 Ramda 的知识,否则是否使用 Ramda 应该是一个问题,它是否使你的代码更易于阅读和编写。它不应该是它自己的目标。
我有一个这样的数组:
[
{
id: '1852',
label: 'One',
types: [1, 2, 4]
},
{
id: '1854852',
label: 'Two',
types: [1, 2]
},
{
id: '4581852',
label: 'Three',
types: [1]
}
]
id属性是唯一的,我用它来获取对象
我有一个对象的变化(例如第三个),我希望它是这样的:
{
id: '4581852',
label: 'new Three',
types: [1, 7, 9]
}
如何对数组进行适当的更改?
因为现在我在做一个不好的解决方案,我试图通过它的id找到元素,从数组中删除它,然后将新对象推入数组,但它总是在最后当然,这不适合我。
如有任何帮助,我们将不胜感激。
您可以使用Array#find
获取对象,然后直接更新其属性。
const arr = [
{
id: '1852',
label: 'One',
types: [1, 2, 4]
},
{
id: '1854852',
label: 'Two',
types: [1, 2]
},
{
id: '4581852',
label: 'Three',
types: [1]
}
]
const obj = arr.find(({id})=>id==='4581852');
obj.label = 'new Three';
obj.types.push(7,9);
console.log(arr);
您可以在 list
中查找 id
并将 object
替换为您找到的内容。
请记住,这种方式 object
必须包含所有属性。
const replace = (list, id, object) => {
const index = list.findIndex(item => item.id === id);
return [...list.slice(0, index), object, ...list.slice(index + 1)]
}
替换 2nd 元素的示例用法:
const list = [
{
id: '1852',
label: 'One',
types: [1, 2, 4]
},
{
id: '1854852',
label: 'Two',
types: [1, 2]
},
{
id: '4581852',
label: 'Three',
types: [1]
}
]
const nextList = replace(list, "1854852", { id: "1854852", label: 'Other Three', types: [1, 2, 3] })
首先,Ramda 不会 帮助您编辑您的值,如果“编辑”是指就地更改。 Ramda(免责声明:我是作者之一)非常注重处理不可变数据。然而,它有许多技术可以帮助您创建数据的更改副本。不过,我不确定它们是否值得,因为相当简单的 ES6 版本也一样干净。
如果您确实想使用 Ramda,一个版本可能如下所示:
const updateAt = (id, transform) =>
map (when (propEq ('id', id), transform))
const data = [{id: '1852', label: 'One', types: [1, 2, 4]}, {id: '1854852', label: 'Two', types: [1, 2]}, {id: '4581852', label: 'Three', types: [1]}]
console.log ( 'Setting the value',
updateAt ('4581852', assoc ('label', 'new Three')) (data)
)
console .log ( 'Updating the value',
updateAt ('1852', evolve ({'label': concat('new ')})) (data)
)
console .log ( 'Original data unchanged', data)
.as-console-wrapper {min-height: 100% !important; top: 0}
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.27.0/ramda.js"></script>
<script> const {map, when, propEq, assoc, evolve, concat} = R </script>
我们展示了两种不同的调用方式:一种是我们将 label
属性 与您的新值相关联。在第二个中,我们通过将 'new '
和当前值连接在一起来改进您的对象。
如果我们愿意,我们可以写一个无积分版本。 Ramda 从早期开始就包含了使之成为可能的工具,尽管它们至少在某种程度上不受核心团队的青睐。其中之一是useWith
,我们可以用它来写这个函数
const updateAt = compose (map, useWith (when, [propEq ('id')]))
不过,我不推荐这样做。初始版本似乎很容易阅读和理解。这个版本更紧凑,但似乎并没有真正从最初的版本中获得任何其他东西,而且可以说更难理解。
第二种可能是使用镜头。 (有几个很好的介绍,包括来自 Richard Tan.) Lenses allow you to focus on a particular part of a data structure, in order to view the value, set it directly, or alter it with a function. Ramda provides these general-purpose functions in view
, set
, and over
. It also has a few function to build lenses, such as lensProp
, lensIndex
, and lensPath
. But we are free to use lens
的一个,用于构建我们自己的,传递 getter 和 setter 函数。
因此我们可以编写一个镜头来查找列表中与特定 属性 匹配的值,并使用它来构建我们的函数。它可能看起来像这样:
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 idLens = lensMatch('id')
const setLabelById = (id, val) =>
set(compose(idLens(id), lensProp('label')), val)
const updateLabelById = (id, fn) =>
over(compose(idLens(id), lensProp('label')), fn)
const data = [{id: '1852', label: 'One', types: [1, 2, 4]}, {id: '1854852', label: 'Two', types: [1, 2]}, {id: '4581852', label: 'Three', types: [1]}]
console .log ( 'Setting the value',
setLabelById ('4581852', 'new Three') (data)
)
console .log ( 'Updating the value',
updateLabelById('4581852', concat('new '))(data)
)
.as-console-wrapper {min-height: 100% !important; top: 0}
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.27.0/ramda.js"></script>
<script> const {lens, find, propEq, findIndex, update, length, over, compose, lensProp, set, concat} = R </script>
同样,我们编写了两个不同版本的函数,具体取决于您是只想设置值还是用函数更新它。
这比原来的版本多了很多代码,所以有人可能会问有什么好处。答案很简单:我们在这里得到两个非常有用的可重用函数:lensMatch
和 idLens
。 lensMatch
让我们定义一个 属性 来检查并关注与 属性 上的给定值匹配的(第一个)元素。 idLens
专门用于 属性 id
。它们有更多的潜在用途并且非常有价值,Ramda 团队真的应该考虑包括它们。 (自我注释...)
稍微想一想,我们可能会想出更多的 Ramda 函数组合来帮助解决这个问题。但我怀疑这是否真的值得,因为你的具体问题可以用一个足够简单的 ES6 函数来解决,根本不用 Ramda。
const setLabelById = (id, val, data, index = data.findIndex(({id: i}) => id == i)) =>
index < 0
? data
: [...data.slice(0, index), {...data[index], label: val}, ...data.slice(index + 1)]
const data = [{id: '1852', label: 'One', types: [1, 2, 4]}, {id: '1854852', label: 'Two', types: [1, 2]}, {id: '4581852', label: 'Three', types: [1]}]
console .log (
setLabelById ('4581852', 'new Three', data)
)
.as-console-wrapper {min-height: 100% !important; top: 0}
我们可以用同样的方式轻松编写一个 updateLabelById
函数。
这项技术与 Dave 的回答有相当多的重叠,但它是从旧条目构建新条目,仅替换 label
属性.
我会非常警惕“使用 Ramda 表达式”这个短语。 Ramda 是一种旨在使以某种风格编写代码更容易的工具。它不是一个框架。除非你将编写代码作为练习来学习更多关于 Ramda 的知识,否则是否使用 Ramda 应该是一个问题,它是否使你的代码更易于阅读和编写。它不应该是它自己的目标。