繁体   English   中英

如何使用 ramda 表达式编辑数组内部的 object?

[英]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 、 setover中提供了这些通用功能。 它还有一些 function 用于构建镜头,例如lensProplensIndexlensPath 但是我们可以自由地使用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 更新它。

这比原始版本要多得多的代码,所以有人可能会问有什么优势。 答案很简单:我们在这里得到了两个非常有用的可重用函数: lensMatchidLens 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM