Scala 中是不是有与 Python 更通用的 map 函数等价的功能?

Posted

技术标签:

【中文标题】Scala 中是不是有与 Python 更通用的 map 函数等价的功能?【英文标题】:Is there an equivalent in Scala to Python's more general map function?Scala 中是否有与 Python 更通用的 map 函数等价的功能? 【发布时间】:2011-02-08 15:50:03 【问题描述】:

我知道 Scala 的 Lists 有一个带有签名 (f: (A) => B):List[B] 的 map 实现和带有签名 (f: (A) => Unit):Unit 的 foreach 实现,但我正在寻找可以像 Python map 一样接受多个迭代的东西接受多个迭代。

我正在寻找带有(f: (A,B) => C, Iterable[A], Iterable[B] ):Iterable[C] 或同等签名的东西。有没有这样的图书馆或类似的类似方式?

编辑:

如下所示,我可以做到

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

但这会在步骤之间创建一个临时列表。如果评论者会发帖,我可以给他投票(提示,提示),但还有其他方法吗?

【问题讨论】:

如果zip() 不起作用,您需要采取哪些不同的措施? 一个...拉链的儿子。对!甚至没有想到这一点。你为什么不发帖让我投票。 我会留给@Mike 回答,但你可以回答list1 zip list2(list1, list2).zipped。后者,仅限 Scala 2.8,不会创建临时集合。此外,您可以分别在 Scala 2.8 和 2.7 上执行 list1.view zip list2list1.projection zip list2 以避免创建临时集合。 不,不,请发帖,这样我也可以投票。其他人可能会在以后问同样的问题。真的,zip 并不是我所需要的全部。我需要对两个列表的成员应用一个函数来生成第三个,即最终列表。 我记得最初的问题是询问 Python 中的解决方案。我要疯了吗? 【参考方案1】:

在 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 不能是 INFINITE Stream。转至Ticket #2634 了解更多信息。 几天前,我在 nabble.com 上有 a post,它表明了我对如何修复这张票的看法。

【讨论】:

【参考方案2】:

您要查找的函数通常称为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
  

这只会遍历一次,因为 zipmap 在迭代器上的实现是完全惰性的。

但是为什么要停在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)

这可以推广到任何数量的函数:

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

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

def zipWith[F[_]:Applicative,A,B,C](f: A => B => C, a: F[A], b: F[B]) =
  (a map f) <*> b

【讨论】:

谢谢。我有很多东西要学。这很有教育意义。【参考方案3】:

在 Scala 2.7(和 2.8,但不推荐使用 zipped)的 List 对象中有一个方法 map2。你可以这样使用它:

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

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

【讨论】:

我很欣赏 2.7 的评论。我很快就会过渡到 2.8。【参考方案4】:

好吧,我不知道语法(f: (A,B) =&gt; C, Iterable[A], Iterable[B] ):Iterable[C](我什么都不知道 Scala),但如果我不得不猜测,它的意思是“A函数 f 采用两个可迭代参数 AB 并返回一个可迭代 C"。我不确定这是否意味着所有可迭代对象产生相同数量的项目。

在 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 的输出只有最短的可迭代对象:

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

无论如何,一些每个人都需要知道但很容易错过的内置 Python 函数:enumeratemapreducezipfilter 曾经在该列表中,但现在使用列表理解更清晰、更灵活。

【讨论】:

以上是关于Scala 中是不是有与 Python 更通用的 map 函数等价的功能?的主要内容,如果未能解决你的问题,请参考以下文章

C++ 中是不是有与 python 中的 astype() 函数等效的函数?

C++ 中是不是有与“for ... else”Python 循环等效的方法?

在 C++/STL 中是不是有与 Python range() 等效的紧凑函数

在 Scala 中是不是有一种通用的方式来记忆?

R 是不是有与 Python 中的 reduce() 等价的东西?

css中是不是有与背景图像等效的前景?