【问题标题】:Nested list filtering & conditional object mapping with Ramda使用 Ramda 的嵌套列表过滤和条件对象映射
【发布时间】:2018-11-18 20:26:48
【问题描述】:

我正试图围绕 Ramda.js,但我被卡住了。我有一个看起来像这样的数组:

const state = [
  {
    itemId: 112,
    animations: [{id: 1}, {id:2}],
    classes: ['animated']    
  },
  {
    itemId: 121,
    animations: [{id:2}],
    classes: ['animated']    
  }
]

我的目标是创建一个函数

removeAnimation(121, 2, state);

...会返回:

const state = [
  {
    itemId: 112,
    animations: [{id: 1}, {id:2}],
    classes: ['animated']    
  },
  {
    itemId: 121,
    animations: [],
    classes: []    
  }
]

所以该函数根据指定itemId的对象内部的指定id移除动画obj,如果animations数组中没有更多对象,它也会移除animated中的字符串classes列表。

这是我走了多远:

const removeAnimationFromItem = R.curry((itemId, animId, state) => {
  return R.map(
    R.when(
      R.propEq('itemId', itemId), [--This is where I'm stuck--]
    ), state)
  })

感谢您的宝贵时间。

【问题讨论】:

  • 你想只使用 ramda.js 来做这个吗?
  • 是的。使用香草 ES6,这不会花很长时间。我正在尝试练习函数式编程,并且该应用程序已经有 Ramda.js。

标签: javascript arrays ramda.js


【解决方案1】:

我认为这里有一个重要的问题,即你是否真的想要 Ramda 的行为。如果我们用 Ramda 做这样的事情,它不会改变你的数据。它将返回与您的原件共享它们可以与您的原件共享的新对象,但您的原件仍将保持原样。 Ramda 团队(免责声明:我是 Ramda 的作者之一)认为这是一件非常好的事情。但有时可能会令人惊讶。

Ramda 没有任何现成的解决方案可以让这变得简单。如果我要这样做,我可能首先将其分解为两个步骤:删除目标动画,然后更新所有项目的 classes 属性。我觉得这更容易思考。如果结果证明存在性能问题,我可能会考虑合并它们。

这是一种方法:

const {findIndex, propEq, adjust, evolve, remove, without, pipe, map} = R

const removeOneAnimation = (itemId, animId, state) => {
  const itemIdx = findIndex(propEq('itemId', itemId), state)
  if (itemIdx < 0) {return state}
  const animIdx = findIndex(propEq('id', animId), state[itemIdx].animations)
  if (animIdx < 0) {return state}
  return adjust(evolve({animations: remove(animIdx, 1)}) , itemIdx, state)
}

const updateAnimClass = (item) => item.animations.length === 0 ? evolve({classes: without(['animated'])}, item) : item

const removeAnimations = pipe(
  removeOneAnimation,
  map(updateAnimClass)
)

const state = [{"animations": [{"id": 1}, {"id": 2}], "classes": ["animated"], "itemId": 112}, {"animations": [{"id": 2}], "classes": ["animated"], "itemId": 121}]

const newState = removeAnimations(121, 2, state)

console.log(newState)
&lt;script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.js"&gt;&lt;/script&gt;

请注意,这里的一些 Ramda 代码并没有提供很大的提升。例如,这个:

  const itemIndex = findIndex(propEq('itemId', itemId), state)

写起来很简单

  const itemIndex = state.findIndex(item => item.itemId === itemId)

但其他一些功能,例如evolveadjustremovewithout 可以做很多事情。如果您希望 Ramda 将数据视为不可变的方法,这些方法相当强大。

【讨论】:

  • 首先非常感谢您抽出宝贵的时间,特别是对 ramda 库 Scott 的感谢。不过,有一个问题,您说“.. 与您的原件分享他们可以分享的内容”。你那是什么意思?你的意思是 state[0].animations[0] === removeAnimations(121, 2, state)[0].animations[0] 是真的吗?这对我来说不是问题,我也认为这是一件好事。我想如果我不希望它们相同,我可以将它们包装在 R.clone() 中。再次感谢。
  • 是的,这正是我的意思。我们发现这种行为很有用,但有些人觉得它令人反感。
猜你喜欢
  • 2015-10-20
  • 2020-06-28
  • 1970-01-01
  • 1970-01-01
  • 2021-08-13
  • 2022-01-06
  • 2011-11-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多