Returning original collection type in generic method

collections, generics, scala

Solution

I think Miles Sabin solution is way too complex. Scala's collection already have the necessary machinery to make it work, with a very small change:

import scala.collection.TraversableLike
def multiMinBy[A, B: Ordering, C <: Traversable[A]]
              (xs: C with TraversableLike[A, C])
              (f: A => B): C = {
  val minVal = f(xs minBy f)
  xs filter (f(_) == minVal)
}

Problem

Say we want to make a function like `minBy` that returns all elements of equal minimalism in a collection: ``` def multiMinBy[A, B: Ordering](xs: Traversable[A])(f: A => B) = { val minVal = f(xs minBy f) xs filter (f(_) == minVal) } scala> multiMinBy(List("zza","zzza","zzb","zzzb"))(_.last) res33: Traversable[java.lang.String] = List(zza, zzza) ``` So far, so good, except that we have a `Traversable` back instead of our initial `List`. So I tried changing the signature to ``` def multiMinBy[A, B: Ordering, C <: Traversable[A]](xs: C)(f: A => B) ``` in the hope I might get a `C` back rather than a `Traversable[A]`. However, I don't get anything back: ``` scala> multiMinBy(List("zza","zzza","zzb","zzzb"))(_.last) <console>:9: error: inferred type arguments [Nothing,Nothing,List[java.lang.String]] do not conform to method multiMinBy's type parameter bounds [A,B,C <: Traversable[A]] ``` I think this is because we have `C` appearing in the arguments before `A` has been inferred? So I flipped the order of the arguments, and added a cast: ``` def multiMinBy[A, B: Ordering, C <: Traversable[A]](f: A => B)(xs: C) = { val minVal = f(xs minBy f) (xs filter (f(_) == minVal)).asInstanceOf[C] } ``` which works, except we have to call it like this: ``` multiMinBy((x: String) => x.last)(List("zza","zzza","zzb","zzzb")) ``` Is there a way to retain the original syntax, while getting the right collection type back?

Original source