I want to define a transformation of a generic collection.
def transform[S<:GenIterable[T],T](s:S):S = s.zipWithIndex
This throws:
type mismatch; found : scala.collection.GenIterable[(T, Int)] required: S
I have to declare S
as a parameterized GenIterable
in the function definition. I'd like to specify an output type of "whatever the collection type was that created S
, except parameterized with [(T,Int)]
", so that I'm guaranteed to get the same collection type back, and not just GenIterable
.
How can I make that happen?
That's my stub on it:
def transform[S[T]<: GenIterableLike[T,S[T]],T](s:S[T])
(implicit bf:CanBuildFrom[S[T],(T,Int),S[(T,Int)]]):S[(T,Int)] = {
s.zipWithIndex
}
Signature is horrible, it may be somewhat simplified (or obscured) by replacing T
with _
.
Trying it out:
scala> val m = Map("x"->"1","y"->"2")
m: scala.collection.Map[String,String] = Map(x -> 1, y -> 2)
scala> transform(m)
res3: Iterable[((String, String), Int)] = List(((x,1),0), ((y,2),1))
scala> val s = Set("x", "y")
s: scala.collection.Set[String] = Set(x, y)
scala> transform(s)
res4: scala.collection.Set[(String, Int)] = Set((x,0), (y,1))
scala> val seq = List("x", "y")
seq: List[String] = List(x, y)
scala> transform(seq)
res5: List[(String, Int)] = List((x,0), (y,1))
The key is to use Like
trait because it carries the type of the collection being used. Then, implicit conversions take care of the rest. Note, how Map
is handled. It seems that implicit conversions default to converting Iterable
to List
, which makes sense.