Я знаю, что Списки 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 его (подсказка, подсказка), но там иначе?
В 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, в котором изложено мое мнение о том, как исправить этот билет.
В 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 (который работает для всех коллекций, а не только для списков).
Функция, которую вы ищете, обычно называется 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
Ну, я не знаю синтаксис (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
. фильтр
раньше был в этом списке, но в наши дни стало более ясным и гибким использовать понимание списка.