Существует ли эквивалент в Scala к более общей функции карты Python?

Я знаю, что Списки Scala имеют реализацию Map с подписью (f: (A) => B):List[B] и foreach реализация с подписью (f: (A) => Unit):Unit но я ищу что-то, что принимает несколько iterables тот же способ, которым карта Python принимает несколько iterables.

Я ищу что-то с подписью (f: (A,B) => C, Iterable[A], Iterable[B] ):Iterable[C] или эквивалентный. Существует ли библиотека, где это существует или сопоставимый способ сделать подобный?

Править:

Как предложено ниже я мог сделать

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

но это создает временный список промежуточные шаги. Если комментатор отправил бы, я мог upvote его (подсказка, подсказка), но там иначе?

9
задан Apocalisp 16 April 2010 в 15:21
поделиться

4 ответа

В scala 2.8 есть метод, называемый zip в Tuple2 и Tuple3, который позволяет избежать создания временной коллекции. Вот несколько примеров использования:

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). zip, убедитесь, что xs не может быть бесконечным потоком. Посетите Билет № 2634 для получения дополнительной информации. Несколько дней назад у меня есть сообщение на nabble.com, в котором изложено мое мнение о том, как исправить этот билет.

12
ответ дан 4 December 2019 в 07:47
поделиться

В Scala 2.7 (и 2.8) есть метод map2 в объекте List в Scala 2.7 (и 2.8, но он устарел в пользу заархивирован ). Вы используете его так:

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

Eastsun уже показал, как использовать заархивированный в 2.8 (который работает для всех коллекций, а не только для списков).

3
ответ дан 4 December 2019 в 07:47
поделиться

Функция, которую вы ищете, обычно называется 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))
}

Оказывается, существует еще более общее выражение этого типа. В общем, конструкторы типов, которые позволяют реализовать этот интерфейс, представляют собой аппликативные функторы

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
11
ответ дан 4 December 2019 в 07:47
поделиться

Ну, я не знаю синтаксис (f: (A, B) => C, Iterable [ A], Iterable [B]): Iterable [C] (и я ничего не знаю Scala), но если бы мне пришлось угадывать, это означало бы «Функция f , принимая два повторяемых аргумента A и B и возвращая итерируемый 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, которые каждый должен знать, но легко упускает из виду: enumerate , map , reduce и zip . фильтр раньше был в этом списке, но в наши дни стало более ясным и гибким использовать понимание списка.

2
ответ дан 4 December 2019 в 07:47
поделиться
Другие вопросы по тегам:

Похожие вопросы: