【问题标题】:What would be a more elegant way of using case class as accumulator in foldLeft?在 foldLeft 中使用案例类作为累加器的更优雅的方式是什么?
【发布时间】:2020-11-16 10:27:07
【问题描述】:

我有一个案例类:

case class Nums(num1: Int, num2: Int)

以及如下列表:

val listOfNums = List(Nums(1,1), Nums(2,2))

我想返回Nums(3,3),它是所有相关字段的总和。我实现这一目标的方法是:

listOfNums.foldLeft(Nums(0,0))((acc,nums) => {
  acc.copy(
    num1 = acc.num1 + nums.num1,
    num2 = acc.num2 + nums.num2
  )
})

但这感觉有点笨拙,正确的方法是什么?

【问题讨论】:

    标签: scala fold


    【解决方案1】:

    其实你要找的是Reduce,而不是fold。你可以试试:

    listOfNums.reduce((num1, num2) => Nums(num1.num1 + num2.num1, num1.num2 + num2.num2))
    

    如果你确实想使用折叠,你不必复制,你可以创建一个新的Nums

    listOfNums.foldLeft(Nums(0,0))((acc,nums) => {
      Nums(
        num1 = acc.num1 + nums.num1,
        num2 = acc.num2 + nums.num2
      )
    })
    

    您可以进一步了解difference between foldLeft and reduceLeft in Scala

    代码运行可以在Scastie找到。

    正如评论中提到的@Thilo,您可以将+ 添加到Nums

    case class Nums(num1: Int, num2: Int) {
      def +(that: Nums): Nums = {
        Nums(num1 + that.num1, num2 + that.num2)
      }
    }
    

    然后foldreduce 的用法变得非常明显:

    listOfNums.reduce(_ + _)
    listOfNums.foldLeft(Nums(0,0))(_ + _)
    

    代码在另一个 Scastie 中运行

    【讨论】:

    • 请注意,reduce 会在空集合上抛出异常。
    【解决方案2】:

    如果您愿意使用cats
    然后,您可以简单地为nums 定义一个Monoid,这样您只需要编写一次样板,然后通过使用combineAllfoldMonoid 等辅助函数在多个部分中重复使用它

    import cats.kernel.Monoid
    final case class Nums(num1: Int, num2: Int)
    object Nums {
      implicit final val NumsMonoid: Monoid[Nums] =
        new Monoid[Nums] {
          override final val empty: Nums =
            Nums(num1 = 0, num2 = 0)
          
          override def combine(n1: Nums, n2: Nums): Nums =
            Nums(num1 = n1.num1 + n2.num1, num2 = n1.num2 + n2.num2)
        }
    }
    

    然后可以像这样使用:

    import cats.syntax.all._
    val listOfNums = List(Nums(1,1), Nums(2,2))
    val result = listOfNums.combineAll
    // result: Nums = Nums(3, 3)
    

    你可以看到代码在运行here

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-12-20
      • 1970-01-01
      • 1970-01-01
      • 2021-01-04
      • 1970-01-01
      • 2015-01-19
      相关资源
      最近更新 更多