代码之家  ›  专栏  ›  技术社区  ›  wheaties

scala中是否有与python更通用的map函数等效的函数?

  •  9
  • wheaties  · 技术社区  · 16 年前

    我知道斯卡拉的名单上有 map 带签名的实现 (f: (A) => B):List[B] 和A foreach 带签名的实现 (f: (A) => Unit):Unit 但是我正在寻找一个接受多个iterables的东西,就像python一样 map 接受多个iterable。

    我在找签名为的东西 (f: (A,B) => C, Iterable[A], Iterable[B] ):Iterable[C] 或同等产品。有没有一个图书馆存在这种情况,或者类似的做法?

    编辑:

    正如下面的建议,我可以做

    val output = myList zip( otherList ) map( x => x(0) + x(1) )
    

    但这在步骤之间创建了一个临时列表。如果评论者发表评论,我可以向他投赞成票(暗示,暗示),但还有别的办法吗?

    4 回复  |  直到 15 年前
        1
  •  12
  •   Eastsun    16 年前

    在scala 2.8中,tuple2&tuple3中有一个名为zipped的方法,它避免了创建临时集合。 下面是一些示例用例:

    Welcome to Scala version 2.8.0.r21561-b20100414020114 (Java HotSpot(TM) Client VM, Java 1.6.0_18).
    Type in expressions to have them evaluated.
    Type :help for more information.
    
    scala> val xs = 0 to 9
    xs: scala.collection.immutable.Range.Inclusive with scala.collection.immutable.Range.ByOne = Range(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
    
    scala> val ys = List.range(0,10)
    ys: List[Int] = List(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
    
    scala> val zs = Array.range(0,10)
    zs: Array[Int] = Array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
    
    scala> (xs,ys).zipped.map{ _+_ }
    res1: scala.collection.immutable.IndexedSeq[Int] = Vector(0, 2, 4, 6, 8, 10, 12, 14, 16, 18)
    
    scala> (zs,ys,xs).zipped.map{ _+_+_ }
    res2: Array[Int] = Array(0, 3, 6, 9, 12, 15, 18, 21, 24, 27)
    
    scala>
    

    tuple2和tuple3中都有一个zip方法。 xs.zip(ys)与(xs,ys).zip相同

    注: 在(xs,ys).zip和(xs,ys).zipped中也存在一些不足,请确保xs不能是无限流。去 Ticket #2634 更多信息。 我有 a post 几天前在nabble.com上看到了我对如何修理这张票的看法。

        2
  •  11
  •   Apocalisp    15 年前

    您要查找的函数通常被调用 zipWith . 不幸的是,标准库中没有提供它,但是它很容易编写:

    def zipWith[A,B,C](f: (A,B) => C, a: Iterable[A], b: Iterable[B]) =
      new Iterable[C] {
        def elements = (a.elements zip b.elements) map f.tupled
      }
    

    这将只遍历一次,因为 zip map 在迭代器上是完全懒惰的。

    但是为什么要停下来 Iterable ?这有一个更一般的形式。我们可以为所有可以用这种方式压缩的数据结构声明一个接口。

    trait Zip[F[_]] {
      def zipWith[A,B,C](f: (A,B) => C, a: F[A], b: F[B]): F[C]
    }
    

    例如,我们可以压缩函数:

    trait Reader[A] {
      type Read[B] = (A => B)
    }
    
    def readerZip[T] = new Zip[Reader[T]#Read] {
      def zipWith[A,B,C](f: (A,B) => C, a: T => A, b: T => B): T => C =
        (t: T) => f(a(t),b(t))
    }
    

    事实证明,这种类型还有一个更通用的表达式。通常,允许实现此接口的类型构造函数是 applicative functors

    trait Applicative[F[_]] {
      def pure[A](a: A): F[A]
      def map[A,B](f: A => B, a: F[A]): F[B]
      def ap[A,B](f: F[A => B], a: F[A]): F[B]
    }
    

    ZipWith的实现如下:

    def zipWith[F[_],A,B,C](f: A => B => C, a: F[A], b: F[B])
                           (implicit m: Applicative[F]) =
      m.ap(m.map(f,a), b)
    

    这概括了任何arity的功能:

      m.ap(m.ap(m.ap(m.map(f,a), b), c), d)
    

    这个 Scalaz 库为标准库中的许多数据结构提供了应用实例。此外,还提供了方便的语法 ap . 在scalaz中,此函数被调用 <*> :

    def zipWith[F[_]:Applicative,A,B,C](f: A => B => C, a: F[A], b: F[B]) =
      (a map f) <*> b
    
        3
  •  3
  •   Rex Kerr    16 年前

    有一种方法 map2 List scala 2.7(和2.8)中的对象,但已弃用它而赞成 zipped )你这样使用它:

    List.map2( List(1,2,3) , List(4,5,6) ) { _ * _ }  // Gives List(4,10,18)
    

    Eastsun已经演示了如何使用 拉链 在2.8中(适用于所有集合,而不仅仅是列表)。

        4
  •  2
  •   Mike DeSimone    16 年前

    嗯,我不知道。 知道 句法 (f: (A,B) => C, Iterable[A], Iterable[B] ):Iterable[C] (我知道) 没有什么 但是如果我不得不猜测的话,这意味着“一个函数 f 接受两个不可辩驳的论点 并返回一个 C “。我不确定这是否意味着所有iterables产生相同数量的项目。

    在python中,我想你在寻找 zip 功能:

    >>> A = range(10, 15)
    >>> B = range(1000, 1500, 100)
    >>> zip(A, B)
    [(10, 1000), (11, 1100), (12, 1200), (13, 1300), (14, 1400)]
    >>> [a + b for a,b in zip(A, B)]
    [1010, 1111, 1212, 1313, 1414]
    

    zip 的输出只与最短的ITerable一样长:

    >>> A=range(10, 12)
    >>> zip(A, B)
    [(10, 1000), (11, 1100)]
    

    总之,有些内置的python函数每个人都需要知道,但很容易遗漏: enumerate , map , reduce 拉链 . filter 以前是在那个列表上,但现在使用列表理解更清晰、更灵活。

    推荐文章