【问题标题】:Map and fold a collection in Scala在 Scala 中映射和折叠集合
【发布时间】:2020-10-06 22:18:53
【问题描述】:

我有一个fold,它遍历元素,依赖地一一修改它们,同时修改它们的父元素。

目前我在fold 中一一替换其父元素中的元素,它们只是少数,这不是真正的性能问题,但我想知道是否有更好的方式来表达这一点。

case class Behavior(x: Int) {
  def simulate(s: Entity): Behavior = copy(x = x + (if (s.alternate) 2 else 1))
}

case class Entity(alternate: Boolean, behaviors: List[Behavior]) {
  def replaceBehavior(o: Behavior, n: Behavior): Entity = {
    copy(behaviors = behaviors.patch(behaviors.indexOf(o), Seq(n), 1))
  }
  def toggleAlternate: Entity = copy(alternate = !alternate)

  def simulate: Entity = {
    behaviors.foldLeft(this) { (e, b) =>
      e.replaceBehavior(b, b.simulate(e)).toggleAlternate
    }    
  }
}

val entity = Entity(false, List(Behavior(10), Behavior(20), Behavior(30)))

entity.simulate

是否有一些操作或巧妙地使用scan 或类似的东西可以让我在一步中执行依赖于foldLeft 结果的foldLeftmap? (我更喜欢 vanilla 标准 Scala 库,但也可以使用函数式框架)。

【问题讨论】:

  • 在真实的代码中,toggleAlternate 是否读取了行为?
  • 在真实代码中b.simulate 生成更新的Behavior 和更新的Entity

标签: scala collections functional-programming


【解决方案1】:

折叠(foldfoldLeftfoldRight、...)通常会将一些 Collection[A] 变成 B

您可以在将结果折叠到 B 之前映射 A - foldMap 映射 A => B 并假设存在 Monoid[B](这在 Cats 中的 Foldable 类型类中可用),因此您将执行转换Collection[A] --using f--> Collection[B] --using Monoid[B]--> B(代码可以对其进行优化,以便在内部使用例如 foldLeft 一步完成操作)。

颠倒操作顺序-我们fold然后我们map-通常是不可能的,因为没有什么可以让我们假设在fold步骤之后我们最终会得到@987654337 @。

根据您的具体用例,我们可能会尝试使用foldMap 来实现您的目标。

【讨论】:

  • "Collection[A] --using f--> Collection[B] --using Monoid[B]--> B" 我不得不承认我不明白这是什么意思。 --using 是什么?这看起来不像 Scala 运算符 - 这是某种符号伪代码符号吗?
  • 这是A ---> B的伪代码,箭头上写着用于执行步骤(函数fMonoid[B])。
猜你喜欢
  • 2011-01-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-04-11
  • 2014-09-21
  • 1970-01-01
  • 2014-01-10
相关资源
最近更新 更多