[英]How can I add cross product based methods to scala collections?
hopefully this will be a simple question about library pimping (because other questions on that subject tend to generate answers beyond my current skill level). 希望这将是一个关于图书馆拉皮条的简单问题(因为关于该主题的其他问题往往会产生超出我目前技能水平的答案)。
All I want to do is map over the cross product of a collection with itself. 我想要做的就是将集合的交叉产品映射到自身。
val distances = points.crossMap(_ distance _) // points: List[Point3d]
So I attempted to pimp Traversable
thus: 所以我试图让皮条客Traversable
:
implicit def toSelfCrossMappable[A](xs: Traversable[A]) = new {
def crossMap[B](f: (A, A) => B) = xs.flatMap(a => xs.map(f(a, _)))
}
But it doesn't work (it's not doing the implicit conversion) and I don't understand why not (I'm pretty new to scala). 但它不起作用(它没有进行隐式转换),我不明白为什么不(我对scala很新)。 I also tried the method suggested in Enriching Scala collections with a method which left me with: 我还尝试了使用一种方法在Enriching Scala集合中建议的方法 :
implicit def toSelfCrossMappable[A, C[A]](xs: C[A])(implicit c: C[A] => Traversable[A]) = new SelfCrossable[A, C[A]](xs)(c)
class SelfCrossable[A, C](xs: C)(implicit c: C => Traversable[A]) {
def crossMap[B](f: (A, A) => B) = xs.flatMap(a => xs.map(f(a, _)))
}
, but that throws the same error as my (simpler looking) way. ,但是抛出与我(看起来更简单)方式相同的错误。
What am I doing wrong here? 我在这做错了什么?
It's not pretty, but this can be done with IsTraversableLike
, 它不漂亮,但可以使用IsTraversableLike
,
import scala.language.implicitConversions
import scala.collection.generic.{ CanBuildFrom, IsTraversableLike }
import scala.collection.GenTraversableLike
class SelfCrossMappable[A, Repr](xs: GenTraversableLike[A, Repr]) {
def crossMap[B, That](f: (A, A) => B)
(implicit
cbf: CanBuildFrom[Repr, B, That],
itl: IsTraversableLike[That] { type A = B }
) = xs.flatMap { a => itl.conversion(xs.map(f(a, _)))
}
}
implicit def toSelfCrossMappable[Repr](xs: Repr)
(implicit traversable: IsTraversableLike[Repr]) =
new SelfCrossMappable(traversable.conversion(xs))
Sample REPL session, 示例REPL会话,
scala> List("foo", "foo", "bar").crossMap(_ == _)
res0: List[Boolean] = List(true, true, false, true, true, false, false, false, true)
In Scala 2.10 you can use implicit classes directly (Miles' answer uses the IsTraversableLike
helper which also requires Scala 2.10). 在Scala 2.10中,您可以直接使用隐式类(Miles的回答使用IsTraversableLike
助手,这也需要Scala 2.10)。 It seems that the toSelfCrossMappable
(horrible name BTW) is not needed for standard collections. 似乎标准集合不需要toSelfCrossMappable
(可怕名称BTW)。 The following works for me: 以下适用于我:
import collection.generic.{CanBuildFrom, IsTraversableLike}
import collection.GenTraversableLike
implicit class CanCrossMap[A, Repr](xs: GenTraversableLike[A, Repr]) {
def crossMap[B, That](f: (A, A) => B)(
implicit cbf: CanBuildFrom[Repr, B, That],
itl: IsTraversableLike[That] { type A = B }): That =
xs.flatMap { a => itl.conversion(xs.map(f(a, _)))
}
}
Another option is to leave out IsTraversableLike
completely: 另一种选择是完全省略IsTraversableLike
:
import collection.GenTraversableOnce
implicit class CanCrossMap[A, Repr](xs: GenTraversableLike[A, Repr]) {
def crossMap[B, That <: GenTraversableOnce[B]](f: (A, A) => B)(
implicit cbf: CanBuildFrom[Repr, B, That]): That =
xs.flatMap { a => xs.map(f(a, _))}
}
Example: 例:
Vector((1.0, 2.0), (3.0, 4.0), (5.0, 6.0)).crossMap { case ((ax, ay), (bx, by)) =>
val dx = bx - ax
val dy = by - ay
math.sqrt(dx*dx + dy*dy)
}
Miles answer covers a few extra cases, where the collection is not directly a GenTraversableLike
, namely Array
and String
(try substituting Vector
for Array
in the last example). 里程答案涵盖了一些额外的案例,其中集合不直接是GenTraversableLike
,即Array
和String
(在最后一个例子中尝试用Vector
代替Array
)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.