3

I want to sum the Map("one" -> 2, "two" -> 3, "three" -> 4)'s values 2+3+4, of course I can use the following methods:

  1. Map("one" -> 2, "two" -> 3, "three" -> 4).foldLeft(0)(_ + _._2)
  2. Map("one" -> 2, "two" -> 3, "three" -> 4).values.sum()

I found Map has a another more direct API sum: def sum: A, but, I don't search any example about this API, How to use it?

Chris Martin
  • 30,334
  • 10
  • 78
  • 137
abelard2008
  • 1,984
  • 1
  • 20
  • 35
  • 1
    That isn't actually the full type signature of `sum`; you may want to read [*Why are scaladoc method signatures wrong?*](https://stackoverflow.com/questions/26132459/why-are-scaladoc-method-signatures-wrong) – Chris Martin Dec 15 '16 at 04:00

2 Answers2

4

For sum[B >: (A, B)](implicit num: Numeric[B]): B, as you see, it needs the implicit parameter and the parameter type is Numeric[B] type.

Scala Numeric is trait that defined a series of math operation. http://www.scala-lang.org/api/current/scala/math/Numeric.html

for your case, the type is Map[String, Int], so you need to implement the implicit for Numeric[(String, Int)] for sum method, like:

 trait MyTupleNumeric extends Numeric[(String, Int)] {
    def plus(x: (String, Int), y: (String, Int)) = ("", x._2 + y._2)

    override def minus(x: (String, Int), y: (String, Int)): (String, Int) = ("", x._2 - x._2)

    override def times(x: (String, Int), y: (String, Int)): (String, Int) = ("", x._2 * y._2)

    override def negate(x: (String, Int)): (String, Int) = ("", -x._2)

    override def fromInt(x: Int): (String, Int) = ("", x)

    override def toInt(x: (String, Int)): Int = x._2

    override def toLong(x: (String, Int)): Long = x._2.toLong

    override def toFloat(x: (String, Int)): Float = x._2.toFloat

    override def toDouble(x: (String, Int)): Double = x._2.toDouble

    override def compare(x: (String, Int), y: (String, Int)): Int = x._2 - y._2
  }

  implicit object MyTupleNumericImplicit extends MyTupleNumeric

  val f = implicitly[Numeric[(String, Int)]] // implicitly is used find implicits base on the type
  println(f.plus(("one", 2), ("two", 3)))
  val r = Map("one" -> 2, "two" -> 3, "three" -> 4)
  println(r.sum._2)
  println(r.sum(MyTupleNumericImplicit))

As the above code, we have implement own Numeric type with (String, Int), and implements methods.

And we implicit this into our scope, so we can use implicitly to get the function and call.

And the sum method also could find the implicit parameter for Numeric[(String, Int)]

chengpohi
  • 14,064
  • 1
  • 24
  • 42
2

The Map.sum method doesn't do what you want -- your functions look good as they are.

The reason why Map has a sum method is that all TraversableOnce classes have a sum method, which only works if the collection type is numeric. However, a Map[K, V] is a TraversableOnce[(K, V)], so this approach won't work (the key-value tuple is not a numeric type).

Tim
  • 3,675
  • 12
  • 25