La función que está buscando generalmente se llama zipWith
. Lamentablemente no está previsto en las bibliotecas estándar, pero es bastante fácil de escribir:
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
}
Este atravesará una sola vez, ya que las implementaciones para zip
y map
sobre iteradores son totalmente perezoso.
¿Pero por qué detenerse en Iterable
? Esto tiene una forma aún más general. Podríamos declarar una interfaz para todas las estructuras de datos que pueden ser comprimidas de esta manera.
trait Zip[F[_]] {
def zipWith[A,B,C](f: (A,B) => C, a: F[A], b: F[B]): F[C]
}
Por ejemplo, podemos comprimir funciones:
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))
}
No resulta ser una expresión más general de este tipo. En general, los constructores de tipos generales que permiten una implementación de esta interfaz son 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]
}
Una implementación de zipWith es entonces simplemente esto:
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)
Esto generaliza a funciones de cualquier aridad:
m.ap(m.ap(m.ap(m.map(f,a), b), c), d)
La biblioteca Scalaz proporciona instancias aplicables para muchas estructuras de datos en la biblioteca estándar. Además, se proporciona una sintaxis conveniente para ap
. En Scalaz, esta función se llama <*>
:
def zipWith[F[_]:Applicative,A,B,C](f: A => B => C, a: F[A], b: F[B]) =
(a map f) <*> b
Si 'postal()' no funciona, ¿qué necesita hacerse de otra manera? –
hijo de ... zip. ¡Righto! Ni siquiera pensé en eso. ¿Por qué no publicas para poder votarlo? – wheaties
Dejaré @Mike para responder, pero puedes hacer 'list1 zip list2' y también' (list1, list2) .zipped'. El último, Scala 2.8 solamente, no crea una colección temporal. Además, puede hacer 'list1.view zip list2' o' list1.projection zip list2' en Scala 2.8 y 2.7 respectivamente para evitar crear colecciones temporales. –