Esiste un equivalente a Scala alla funzione mappa più generale di Python?
-
27-09-2019 - |
Domanda
So che Le liste di Scala hanno un mappa implementazione con la firma (f: (A) => B):List[B]
ed un foreach implementazione con la firma (f: (A) => Unit):Unit
ma sto cercando qualcosa che accetta più iterables allo stesso modo in cui il Python mappa accetta più iterabili.
Sto cercando qualcosa con una firma di (f: (A,B) => C, Iterable[A], Iterable[B] ):Iterable[C]
o equivalente. C'è una biblioteca dove questo esiste o un modo comparabile di fare simile?
Modifica:
Come suggerito di seguito ho potuto fare
val output = myList zip( otherList ) map( x => x(0) + x(1) )
, ma che crea un elenco temporaneo tra i passaggi. Se il commentor avrebbe inviare l'ho (suggerimento, suggerimento) potrebbe upvote, ma c'è un altro modo?
Soluzione
In Scala 2.8, c'è un metodo chiamato con zip in Tuple2 & Tuple3 che evitano di creare raccolta temporanea. Ecco qualche caso d'uso del campione:
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>
C'è un metodo zip sia Tuple2 e Tuple3. xs.zip (ys) è uguale a (xs, ys) .zip
Nota: C'è anche una certa carenza di (xs, ys) .zip e (xs, ys) .zipped, assicurarsi che xs non può essere un'INFINITE Stream. Vai a biglietto # 2634 per ulteriori informazioni. Ho un post in nabble.com qualche giorno fa, che mostra le mie opinioni su come risolvere questo biglietto.
Altri suggerimenti
La funzione che stai cercando è di solito chiamato zipWith
. Non è purtroppo previsto nelle librerie standard, ma è abbastanza facile da scrivere:
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
}
Questo attraversare solo una volta, dal momento che le implementazioni per zip
e map
su iteratori sono completamente pigri.
Ma perché fermarsi a Iterable
? Questo ha una forma ancora più generale. Potremmo dichiarare un interfaccia per tutte le strutture di dati che possono essere compressi in questo modo.
trait Zip[F[_]] {
def zipWith[A,B,C](f: (A,B) => C, a: F[A], b: F[B]): F[C]
}
Per esempio, possiamo comprimere funzioni:
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))
}
Ci si rivela essere un'espressione ancora più generale di questo tipo. In generale, digitare i costruttori che permettono l'implementazione di questa interfaccia sono applicativo funtori
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]
}
Un'implementazione di zipWith è quindi solo questo:
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)
Questa generalizza alle funzioni di qualsiasi arità:
m.ap(m.ap(m.ap(m.map(f,a), b), c), d)
Il Scalaz libreria fornisce esempi applicativi per un sacco di strutture di dati nella libreria standard . Inoltre, la sintassi vantaggiosa è previsto ap
. In Scalaz, questa funzione viene chiamata <*>
:
def zipWith[F[_]:Applicative,A,B,C](f: A => B => C, a: F[A], b: F[B]) =
(a map f) <*> b
C'è un metodo map2
nell'oggetto List
a Scala 2.7 (e 2.8, ma è sconsigliata a favore di zipped
). Si utilizza in questo modo:
List.map2( List(1,2,3) , List(4,5,6) ) { _ * _ } // Gives List(4,10,18)
di Eastsun già mostrato come utilizzare zipped
a 2.8 (che funziona su tutte le collezioni, non solo le liste).
Beh, non mi so il (f: (A,B) => C, Iterable[A], Iterable[B] ):Iterable[C]
sintassi (e so non di Scala), ma se ho dovuto indovinare, significherebbe "Una funzione < em> f di prendere due argomenti iterabili A e B e la restituzione di un iterabile C ". Non sono sicuro se questo implica che tutte le iterables producono lo stesso numero di elementi.
In Python, credo che tu stia cercando il zip funzione :
>>> 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]
uscita di zip
è solo fino a quando il più breve iterabile:
>>> A=range(10, 12)
>>> zip(A, B)
[(10, 1000), (11, 1100)]
In ogni caso, alcuni built-in Python funzioni ognuno deve sapere poco facilmente: enumerate
, map
, reduce
e zip
. filter
usato per essere in quella lista, ma è più chiara e più flessibile per utilizzare un elenco di comprensione in questi giorni.