在 foldLeft 中使用 case class 作为累加器的更优雅的方法是什么?
What would be a more elegant way of using case class as accumulator in foldLeft?
我有一个案例class:
case class Nums(num1: Int, num2: Int)
以及如下列表:
val listOfNums = List(Nums(1,1), Nums(2,2))
我想return Nums(3,3)
这是所有相关字段的总和。我实现这一目标的方法是:
listOfNums.foldLeft(Nums(0,0))((acc,nums) => {
acc.copy(
num1 = acc.num1 + nums.num1,
num2 = acc.num2 + nums.num2
)
})
但是这样感觉有点笨拙,请问怎样才是正确的做法呢?
实际上您要查找的是 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)
}
}
然后 fold
和 reduce
用法变得非常明显:
listOfNums.reduce(_ + _)
listOfNums.foldLeft(Nums(0,0))(_ + _)
代码 运行 在另一个 Scastie
如果您愿意使用 cats。
然后,您可以简单地为 nums
定义一个 Monoid
这样您只需要编写一次样板文件,然后通过使用 combineAll
或 [=15= 等辅助功能在多个部分重复使用它]
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.
我有一个案例class:
case class Nums(num1: Int, num2: Int)
以及如下列表:
val listOfNums = List(Nums(1,1), Nums(2,2))
我想return Nums(3,3)
这是所有相关字段的总和。我实现这一目标的方法是:
listOfNums.foldLeft(Nums(0,0))((acc,nums) => {
acc.copy(
num1 = acc.num1 + nums.num1,
num2 = acc.num2 + nums.num2
)
})
但是这样感觉有点笨拙,请问怎样才是正确的做法呢?
实际上您要查找的是 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)
}
}
然后 fold
和 reduce
用法变得非常明显:
listOfNums.reduce(_ + _)
listOfNums.foldLeft(Nums(0,0))(_ + _)
代码 运行 在另一个 Scastie
如果您愿意使用 cats。
然后,您可以简单地为 nums
定义一个 Monoid
这样您只需要编写一次样板文件,然后通过使用 combineAll
或 [=15= 等辅助功能在多个部分重复使用它]
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.