简体   繁体   English

如何将基于交叉产品的方法添加到scala集合?

[英]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 ,即ArrayString (在最后一个例子中尝试用Vector代替Array )。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM