[英]How to convert an array containing arrays of objects to single array witht hose object using Ramda expressions?
[英]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 属性是唯一的,我用它来获取 object。
我在一个 object (例如第三个)中进行了更改,我希望它是这样的:
{
id: '4581852',
label: 'new Three',
types: [1, 7, 9]
}
如何对阵列进行适当的更改?
因为现在我在做一个不好的解决方案,我试图通过它的 id 找到元素,将它从数组中删除,然后将新的 object 推入数组,但它总是在列表的末尾,当然,不适合我。
任何帮助将非常感激。
您可以使用Array#find
获取 object,然后直接更新其属性。
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);
首先,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 '
和当前值连接在一起来改进您的 object。
如果我们愿意,我们可以编写一个无点版本。 Ramda 从早期就包含了使之成为可能的工具,尽管它们至少在某种程度上已经不受核心团队的青睐。 其中之一是useWith
,我们可以用它来写这个 function 为
const updateAt = compose (map, useWith (when, [propEq ('id')]))
不过,我不会推荐这个。 最初的版本似乎很容易阅读和理解。 这个版本更紧凑,但似乎并没有在最初的版本中获得任何其他东西,并且可以说更难以理解。
第二种可能性是使用镜头。 (有几个很好的介绍,包括Richard Tan的介绍。) Lenses 允许您专注于数据结构的特定部分,以便查看值、直接设置它或使用 function 更改它。 view
在 view 、 set
和over
中提供了这些通用功能。 它还有一些 function 用于构建镜头,例如lensProp
、 lensIndex
和lensPath
。 但是我们可以自由地使用lens
来构建我们自己的,传递 getter 和 setter 函数。
因此我们可以编写一个镜头来在列表中查找与特定属性匹配的值,并使用它来构建我们的 function。 它可能看起来像这样:
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>
同样,我们编写了 function 的两个不同版本,具体取决于您只是想设置值还是使用 function 更新它。
这比原始版本要多得多的代码,所以有人可能会问有什么优势。 答案很简单:我们在这里得到了两个非常有用的可重用函数: lensMatch
和idLens
。 lensMatch
让我们定义一个属性来检查并关注与该属性的给定值匹配的(第一个)元素。 idLens
专门用于处理属性id
。 这些有更多的潜在用途,并且足够有价值,Ramda 团队真的应该考虑将它们包括在内。 (注意自我...)
稍加思考,我们可能会想到更多 Ramda 函数的组合来帮助解决这个问题。 但我怀疑这是否真的值得,因为您的具体问题可以通过一个足够简单的 ES6 function 完全不使用 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
function。
这种技术与 Dave 的答案有相当多的重叠,但它从旧条目中构建了新条目,仅替换了label
属性。
我会非常警惕“使用 Ramda 表达式”这个短语。 Ramda 是一种工具,旨在使以某种风格编写更容易。 它不是一个框架。 除非你编写代码是为了更多地了解Ramda,否则是否使用 Ramda 应该是一个问题,即它是否使你的代码更易于阅读和编写。 它不应该是它自己的目标。
您可以在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)]
}
替换第二个元素的示例用法:
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] })
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.