Reputation: 2552
I just need to reduce the elements in a collection but I'd like to keep the collection in the result.
scala> List("a","b","c").reduce(_+_)
res0: String = abc
I'd like to get
scala> List("a","b","c").someSortOfReduce(_+_)
res0: List[String] = List(abc)
scala> Seq("a","b","c").someSortOfReduce(_+_)
res1: Seq[String] = Seq(abc)
Upvotes: 2
Views: 218
Reputation: 1705
Use the companion
method
def red[T](a: Iterable[T], f: (T,T) => T) = a.companion(a.reduce(f))
EDITED
If you need to preserve the static type an option is to use asInstanceOf
implicit class Reduce[T, C[T] <: Iterable[T]](s: C[T]) {
def someSortOfReduce(f: (T, T) => T): C[T] = s.companion(s.reduce(f)).asInstanceOf[C[T]]
}
val list = List(1, 2, 3).someSortOfReduce(_ + _) // list: List[Int] = List(6)
val set = Set(1, 2, 3).someSortOfReduce(_ + _) // set: Set[Int] = Set(6)
or Pattern Matching
implicit class Reduce[T, C[T] <: Iterable[T]](s: C[T]) {
def someSortOfReduce(f: (T, T) => T): C[T] = s.companion(s.reduce(f)) match {
case a: C[T] => a
}
}
Upvotes: 2
Reputation: 32719
Here is one way to do it (maybe not the most elegant, but hey, it works):
import collection.generic._
def reduceAsCollection[E,C[_]](s: C[E])(f: (E,E) => E)(implicit cbf: CanBuildFrom[Nothing, E, C[E]], e: C[E] <:< TraversableOnce[E]): C[E] = {
(cbf() += s.reduce(f)).result
}
And the obligatory REPL test:
scala> reduceAsCollection(List("a","b","c"))(_+_)
res14: List[String] = List(abc)
scala> reduceAsCollection(Seq("a","b","c"))(_+_)
res15: Seq[String] = Vector(abc)
As you can see, not only has the resulting collection an appropriate runtime type, but the static type is also preserved (give a Seq
get a Seq
back, give a List
, get a List
back).
Upvotes: 3
Reputation: 2552
I found the solution myself
val list = List("a","b","c")
list.companion(list.reduce(_+_))
Upvotes: 1
Reputation: 7553
Since the collection you want and the original collection don't share any entries, you could just wrap the result of the reduce in whatever you want.
Seq(original.reduce(_+_))
Upvotes: 0