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

前端 未结 3 2042
无人及你
无人及你 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条回答
  •  梦毁少年i
    2021-02-04 12:20

    To be honest I'm not sure how that really works:

    implicit def collectionExtras[CC[X] <: Iterable[X], A](xs: CC[A]) = new {
      import collection.generic.CanBuildFrom
      def zipWith[B, C](ys: Iterable[B])(f: (A, B) => C)
      (implicit cbf:CanBuildFrom[Nothing, C, CC[C]]): CC[C] = {
        xs.zip(ys).map(f.tupled)(collection.breakOut)
      }
    }
    
    scala> Vector(2, 2, 2).zipWith(Vector(4, 4, 4))(_ * _)
    res1: scala.collection.immutable.Vector[Int] = Vector(8, 8, 8)
    

    I sort of monkey patched this answer from retronym until it worked!

    Basically, I want to use the CC[X] type constructor to indicate that zipWith should return the collection type of xs but with C as the type parameter (CC[C]). And I want to use breakOut to get the right result type. I sort of hoped that there was a CanBuildFrom implicit in scope but then got this error message:

    required: scala.collection.generic.CanBuildFrom[Iterable[(A, B)],C,CC[C]]
    

    The trick was then to use Nothing instead of Iterable[(A, B)]. I guess that implicit is defined somewhere...

    Also, I like to think of your zipWith as zip and then map, so I changed the implementation. Here is with your implementation:

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

    Note this article provides some background on the type constructor pattern.

提交回复
热议问题