2011-11-22 18 views
16

たちは、コレクションに等しいミニマリズムのすべての要素を返すminByような関数を作りたいと言います私たちの最初のListの代わりに。一般的な方法では、元のコレクション型を返す

だから、私はCバックではなくTraversable[A]得る可能性があります期待して

def multiMinBy[A, B: Ordering, C <: Traversable[A]](xs: C)(f: A => B) 

に署名を変更してみました。しかし、私は何も戻って得ることはありません:

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]] 

私たちはAが推察された前の引数に現れるCを持っているので、これがあると思いますか?だから私は、引数の順序を反転して、キャストを追加しました:

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] 
} 

働く、私たちはこのようにそれを呼び出す必要があり除い:

multiMinBy((x: String) => x.last)(List("zza","zzza","zzb","zzzb")) 

を元の構文を保持する方法はあります、適切なコレクションタイプを取得していますか?

答えて

20

私はMiles Sabinのソリューションはあまりにも複雑だと思います。 Scalaのコレクションは、すでに非常に小さな変更で、それを動作させるために必要な機械を持っている:

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) 
} 
+3

はい、私は同意します、これは私より良い解決策です。 –

10

あなたの問題は、(私はこの答えにTraversable[A]の代わりに使用します)GenTraversable[A]にする方法として見たときfilterメソッドの結果タイプがGenTraversable[A]以下より正確ではないということです。残念なことに、multiMinByメソッドの本文に書かれているように、皆あなたが知っているのはxsです。

この結果を得るには、multiMinByの署名をより正確にする必要があります。まだ比較的オープンタイプの容器を残しながらこれを行う1つの方法は、次のように構造型を使用することで、

type HomFilter[CC[X] <: GenTraversable[X], A] = 
    CC[A] { def filter(p : A => Boolean) : CC[A] } 

def multiMinBy[CC[X] <: GenTraversable[X], A, B: Ordering] 
    (xs: HomFilter[CC, A])(f: A => B) : CC[A] = { 
    val minVal = f(xs minBy f) 
    xs filter (f(_) == minVal) 
    } 

構造型HomFiltermultiMinByの引数が望ましいとfilterメソッドを持たなければならないと主張するために私達を許可します結果の型。 GenTraversableのサブタイプは、このように定期的ではありませんfilterメソッドを定義することは許さだ:これは、コンテナがちょうどTraversableことがより厳しい要件であることを念頭に置いて

サンプルREPLセッション、

scala> val mmb = multiMinBy(List("zza","zzza","zzb","zzzb"))(_.last) 
mmb: List[String] = List(zza, zzza) 

ベア。上記の署名は、そのような型の値が静的にmultiMinByに渡されるのを防ぐでしょう...おそらくそれはあなたの後の動作です。

+0

一つは、単に 'TraversableLike'を使用することによって、全体の構造タイピングブツを回避することができます。 –

13

CanBuildFromはどうですか?

import scala.collection.immutable._ 
import scala.collection.generic._ 

def multiMinBy[A, B, From[X] <: Traversable[X], To](xs: From[A])(f: A => B) 
    (implicit ord: Ordering[B], bf: CanBuildFrom[From[_], A, To]) = { 
    val minVal = f(xs minBy f) 
    val b = bf() 
    b ++= (xs filter (f(_) == minVal)) 
    b.result 
} 



scala> multiMinBy(List("zza","zzza","zzb","zzzb"))(_.last) 
res1: List[java.lang.String] = List(zza, zzza) 
関連する問題