How to write a zipWith method that returns the same type of collection as those passed to it?

前端 未结 3 2040
无人及你
无人及你 2021-02-04 11:21

I have reached this far:

implicit def collectionExtras[A](xs: Iterable[A]) = new {
  def zipWith[B, C, That](ys: Iterable[B])(f: (A, B) => C)(implicit cbf: Ca         


        
3条回答
  •  [愿得一人]
    2021-02-04 12:00

    You got close enough. Just a minor change in two lines:

    implicit def collectionExtras[A, CC[A] <: IterableLike[A, CC[A]]](xs: CC[A]) = new {
      def zipWith[B, C, That](ys: Iterable[B])(f: (A, B) => C)(implicit cbf: CanBuildFrom[CC[A], C, That]) = {
        val builder = cbf(xs.repr)
        val (i, j) = (xs.iterator, ys.iterator)
        while(i.hasNext && j.hasNext) {
          builder += f(i.next, j.next)
        }
        builder.result
      }
    }
    

    First, you need to get the collection type being passed, so I added CC[A] as a type parameter. Also, that collection needs to be able to "reproduce" itself -- that is guaranteed by the second type parameter of IterableLike -- so CC[A] <: IterableLike[A, CC[A]]. Note that this second parameter of IterableLike is Repr, precisely the type of xs.repr.

    Naturally, CanBuildFrom needs to receive CC[A] instead of Iterable[A]. And that's all there is to it.

    And the result:

    scala> Vector(2, 2, 2).zipWith(Vector(4, 4, 4))(_ * _)
    res0: scala.collection.immutable.Vector[Int] = Vector(8, 8, 8)
    

提交回复
热议问题