¿Hay un equivalente en la Scala de función de mapa más general de Python?
-
27-09-2019 - |
Pregunta
Yo sé que las listas de Scala tienen un mapa aplicación con (f: (A) => B):List[B]
firma y una foreach aplicación con la firma (f: (A) => Unit):Unit
pero estoy buscando algo que acepta múltiples iterables de la misma manera que el pitón mapa acepta múltiples iterables.
Estoy buscando algo, con una firma de (f: (A,B) => C, Iterable[A], Iterable[B] ):Iterable[C]
o equivalente. ¿Hay una biblioteca siempre que exista o una manera de hacer comparables similar?
Editar:
Como se sugiere a continuación que podía hacer
val output = myList zip( otherList ) map( x => x(0) + x(1) )
sino que crea una lista temporal entre los pasos. Si el commentor registraría que él (pista, pista) pudiera upvote pero ¿hay otra forma?
Solución
En Scala 2.8, hay un método llamado cremallera en Tuple2 y Tuple3 que eviten crear colección temporal. He aquí algunos casos de uso de ejemplo:
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>
Hay un método de cremallera tanto en Tuple2 y Tuple3. xs.zip (ys) es lo mismo que (xs, ys) .zip
Nota: Hay también una cierta escasez de (xs, ys) .zip y (xs, ys) .zipped, asegúrese de que x no puede ser un flujo infinito. Ir a Ticket # 2634 para más información. Tengo un post en nabble.com hace unos días, que muestra mis opiniones sobre cómo solucionar este billete.
Otros consejos
La función que está buscando es usualmente llamado 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
}
Esto atravesar una sola vez, ya que las implementaciones para zip
y map
en iteradores son totalmente perezoso.
Pero por qué parada en Iterable
? Esto tiene una forma aún más general. Podríamos declarar una interfaz para todas las estructuras de datos que puede ser comprimido 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 que permiten una implementación de esta interfaz son aplicativo funtores
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 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)
Este generaliza a funciones de cualquier aridad:
m.ap(m.ap(m.ap(m.map(f,a), b), c), d)
El Scalaz biblioteca proporciona casos aplicativos para una gran cantidad de estructuras de datos en la biblioteca estándar . Además, se proporciona la 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
Hay una map2
método en el objeto List
en Scala 2.7 (y 2.8, pero está desfasada y en zipped
). Lo usa de esta manera:
List.map2( List(1,2,3) , List(4,5,6) ) { _ * _ } // Gives List(4,10,18)
de Eastsun que se muestran cómo utilizar zipped
en 2.8 (que funciona en todas las colecciones, no sólo las listas).
Bueno, no me sabe (f: (A,B) => C, Iterable[A], Iterable[B] ):Iterable[C]
la sintaxis (y sé no de Scala), pero si tuviera que adivinar, que significaría "Una función < em> f tomar dos argumentos iterables A y B y devolver un iterable C ". No estoy seguro de si esto implica que todos los iterables dan el mismo número de elementos.
En Python, creo que estás en busca de la zip función :
>>> 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]
La producción de zip
es sólo el tiempo que el menor iterable:
>>> A=range(10, 12)
>>> zip(A, B)
[(10, 1000), (11, 1100)]
De todas formas, algunas de ellas construidas en Python necesidades funciones que cada uno supiera, pero no alcanza fácilmente: enumerate
, map
, reduce
y zip
. filter
utiliza para estar en esa lista, pero es más clara y más flexible de usar una lista por comprensión en estos días.