Search code examples
scalafold

What would be a more elegant way of using case class as accumulator in foldLeft?


I have a case class:

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

and a list as follows:

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

I want to return Nums(3,3) which is the sum of all the relevant fields with each other. The way I achieved this was:

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

But this feels a bit clumsy, what would be the right way?


Solution

  • Actually what you are looking for is Reduce, and not fold. You can try:

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

    If you do want to use fold, you don't have to copy, you can just create a new Nums:

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

    You can further read about difference between foldLeft and reduceLeft in Scala.

    Code run can be found at Scastie.

    As @Thilo mentioned in the comment, you can add a + to Nums:

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

    And then the fold and reduce usage become really obviuos:

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

    Code run for that in another Scastie