Я хотел бы иметь функцию groupByIndex
, которая группирует значения на основе их индекса (а не значения). Конкретное определение метода для Vector[A]
может выглядеть следующим образом:Как создать универсальную функцию groupByIndex?
def groupByIndex[A, K](vector: Vector[A], f: Int => K): immutable.Map[K, Vector[(A, Int)]] = {
vector.zipWithIndex.groupBy { case (elem, index) => f(index) }
}
тестирования этой функции в REPL дает действительно правильный результат:
scala> val vec = Vector.tabulate(4)(i => s"string ${i+1}")
vec: scala.collection.immutable.Vector[String] = Vector(string 1, string 2, string 3, string 4)
scala> groupByIndex(vec, i => i%2)
res2: scala.collection.immutable.Map[Int,Vector[(String, Int)]] = Map(1 -> Vector((string 2,1), (string 4,3)), 0 -> Vector((string 1,0), (string 3,2)))
Теперь я хотел бы применить «enrich- my-library ", чтобы дать этот метод всем классам, которые должны его поддерживать, т.е. классы, которые реализуют zipWithIndex
и groupBy
. Эти два метода определены в GenIterableLike
(zipWithIndex
) и GenTraversableLike
/TraversableLike
(groupBy
).
С учетом всего этого, я пытался имитировать определения метод zipWithIndex
(это проблематично) и groupBy
построить мой собственный groupByIndex
:
implicit class GenIterableLikeOps[A, Repr](val iterable: GenIterableLike[A, Repr] with TraversableLike[A, Repr]) extends AnyVal {
def groupByIndex[K, A1 >: A, That <: TraversableLike[(A1, Int), OtherRepr], OtherRepr](f: Int => K)(implicit bf: CanBuildFrom[Repr, (A1, Int), That]): immutable.Map[K, OtherRepr] = {
val zipped = iterable.zipWithIndex
zipped.groupBy{ case (elem, index) => f(index) }
}
}
Во-первых, это кажется слишком сложным для меня - есть ли способ упростить это? Например, можем ли мы каким-то образом отказаться от второго OtherRepr
? (Я не смог.) Во-вторых, я не могу вызвать эту функцию без явного указания общих параметров. Используя пример из выше я получаю следующее сообщение об ошибке:
scala> vec.groupByIndex(i => i%2)
<console>:21: error: Cannot construct a collection of type scala.collection.TraversableLike[(String, Int),Nothing] with elements of type (String, Int) based on a collection of type scala.collection.immutable.Vector[String].
vec.groupByIndex(i => i%2)
^
scala> vec.groupByIndex[Int, String, Vector[(String, Int)], Vector[(String, Int)]](i => i%2)
res4: scala.collection.immutable.Map[Int,Vector[(String, Int)]] = Map(1 -> Vector((string 2,1), (string 4,3)), 0 -> Vector((string 1,0), (string 3,2)))
Как а) упростить этот метод и б) заставить его работать без необходимости указывать общие параметры?