Нет ничего встроенного, но вы можете написать это так:
def reduceByKey[A, B](items: Traversable[(A, B)])(f: (B, B) => B): Map[A, B] = {
var result = Map.empty[A, B]
items.foreach {
case (a, b) =>
result += (a -> result.get(a).map(b1 => f(b1, b)).getOrElse(b))
}
result
}
Есть место для оптимизации (например, используйте изменяемые карты), но общая идея остается прежней.
Другой подход, более декларативный, но менее эффективный (создает несколько промежуточных коллекций; может быть переписан, но с потерей ясности:
def reduceByKey[A, B](items: Traversable[(A, B)])(f: (B, B) => B): Map[A, B] = {
items
.groupBy { case (a, _) => a }
.mapValues(_.map { case (_, b) => b }.reduce(f))
// mapValues returns a view, view.force changes it back to a realized map
.view.force
}