コメントのいくつかの提案に従って、私はCanBuildFromを調べました、そしてこれは私が思いついたものです:
import scala.collection.IterableLike
import scala.collection.generic.CanBuildFrom
/** Filters `xs` to have only every nth element.
*/
def everyNth[A, It <: Iterable[A]]
(xs: It with IterableLike[A, It], n: Int, offset: Int = 0)
(implicit bf: CanBuildFrom[It, A , It]): It = {
val retval = bf()
retval ++= xs.zipWithIndex collect { case (x, i) if (i - offset) % n == 0 => x }
retval.result
}
はい、動作します!!!
そして、キャストはありません。そのため、範囲でも機能します。
ただし、空のretvalから始めて、それを埋めるために「++ =」を使用する必要があるのは少しエレガントではないように思われるので、誰かがよりエレガントな解決策を持っているなら、私はすべての耳です。
戻り型が引数型と同じではないため、上記よりも少しトリッキーな、私が実装した別のジェネリック関数を次に示します。つまり、入力は一連のA
'sですが、出力は一連の(A, A)
'sです。
def zipWithSelf[A, It[A] <: Iterable[A]]
(xs: It[A] with IterableLike[A, It[A]])
(implicit bf: CanBuildFrom[It[A], (A, A), It[(A, A)]]): It[(A, A)] = {
val retval = bf()
if (xs.nonEmpty) {
retval ++= xs zip xs.tail
retval.result
} else retval.result
}
そしてここに別のものがあります:
/** Calls `f(x)` for all x in `xs` and returns an Iterable containing the indexes for
* which `f(x)` is true.
*
* The type of the returned Iterable will match the type of `xs`.
*/
def findAll[A, It[A] <: Iterable[A]]
(xs: It[A] with IterableLike[A, It[A]])
(f: A => Boolean)
(implicit bf: CanBuildFrom[It[A], Int, It[Int]]): It[Int] = {
val retval = bf()
retval ++= xs.zipWithIndex filter { p => f(p._1) } map { _._2 }
retval.result
}
「いいね」の種類やについてはまだよくわかりませんがCanBuildFrom
、要点はわかります。また、ほとんどの場合、ジェネリック関数のキャストバージョンを最初のパスとして記述し、次にボイラープレートを追加して、関数をより一般的で完全に型安全にするのは簡単CanBuildFrom
ですIterableLike
。