2010-04-16 3 views
9

Ich weiß, dass Scala Listen haben eine map Implementierung mit Unterschrift (f: (A) => B):List[B] und eine foreach Umsetzung mit Unterschrift (f: (A) => Unit):Unit aber ich bin auf der Suche nach etwas, das mehr Iterables die gleiche Art und Weise akzeptiert, dass der Python map mehr Iterables akzeptiert.Gibt es ein Äquivalent in Scala zu Pythons allgemeinere Map-Funktion?

Ich suche nach etwas mit einer Signatur von (f: (A,B) => C, Iterable[A], Iterable[B]):Iterable[C] oder gleichwertig. Gibt es eine Bibliothek, wo dies existiert oder eine vergleichbare Vorgehensweise?

Edit:

Wie vorgeschlagen unten I

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

tun könnte, aber das erzeugt eine temporäre Liste in zwischen den Schritten. Wenn der Kommentator schreiben würde, könnte ich ihn aufrütteln (Hinweis, Hinweis), aber gibt es einen anderen Weg?

+2

Wenn 'zip()' nicht funktioniert, was brauchen Sie anders gemacht? –

+0

Sohn eines ... zip. Richtig! Hab nicht mal daran gedacht. Warum postest du nicht, damit ich es aufbessern kann? – wheaties

+4

Ich lasse @Mike antworten, aber Sie können 'list1 zip list2' und auch' (list1, list2) .zip' machen. Letzteres, nur Scala 2.8, erstellt keine temporäre Sammlung. Sie können auch 'list1.view zip list2' oder' list1.projection zip list2' auf Scala 2.8 bzw. 2.7 ausführen, um das Erstellen temporärer Sammlungen zu vermeiden. –

Antwort

12

In scala 2.8 gibt es eine Methode namens Zip in Tuple2 & Tuple3, die vermeiden, temporäre Sammlung zu erstellen. Hier einige Beispiel-Use-Case:

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> 

Es ist eine ZIP-Methode in beiden Tuple2 und Tuple3. xs.zip (ys) ist das gleiche wie (xs, ys) .zip

Hinweis: Es gibt auch einigen Mangel in (xs, ys) .zip und (xs, ys) .zipped, stellen Sie sicher, dass xs kein INFINITE Stream sein kann. Weitere Informationen finden Sie unter Ticket #2634. Ich habe a post in nabble.com vor einigen Tagen die meine Meinungen über zeigt, wie dieses Ticket zu beheben.

3

Es gibt eine Methode map2 in der List Objekt in Scala 2.7 (und 2.8, aber es ist veraltet zugunsten zipped). Sie verwenden es, wie so:

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

Eastsun ist bereits gezeigt, wie zipped in 2.8 verwenden (die auf allen Sammlungen funktioniert, nicht nur auflistet).

+0

Ich schätze den 2.7 Kommentar. Ich werde bald zu 2.8 wechseln. – wheaties

2

Nun, ich nicht wissen die Syntax (f: (A,B) => C, Iterable[A], Iterable[B]):Iterable[C] (und ich weiß nichts von Scala), aber wenn ich raten müsste, würde es bedeuten, „Eine Funktion f zwei iterable Argumente nehmen A und B und Zurücksenden eines iterable C“. Ich bin mir nicht sicher, ob dies bedeutet, dass alle Iterables die gleiche Anzahl an Items ergeben.

In Python, ich glaube, du bist für die zip Funktion suchen:

>>> 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 ‚s Ausgang ist nur so lang wie die kürzeste iterable:

>>> A=range(10, 12) 
>>> zip(A, B) 
[(10, 1000), (11, 1100)] 

Wie auch immer, einige eingebaute in Python braucht Funktionen jeder vermisst wissen aber leicht: enumerate, map, reduce und zip.filter war früher auf dieser Liste, aber es ist klarer und flexibler, ein Listenverständnis in diesen Tagen zu verwenden.

11

Die Funktion, nach der Sie suchen, wird normalerweise zipWith genannt. Es ist leider nicht in den Standardbibliotheken zur Verfügung gestellt, aber es ist ziemlich einfach zu schreiben:

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 
    } 

Diese nur einmal durchlaufen werden, da die Implementierungen für zip und map auf Iteratoren voll faul sind.

Aber warum aufhören bei Iterable? Dies hat eine noch allgemeinere Form. Wir könnten eine Schnittstelle für alle Datenstrukturen deklarieren, die auf diese Weise gezippt werden können.

trait Zip[F[_]] { 
    def zipWith[A,B,C](f: (A,B) => C, a: F[A], b: F[B]): F[C] 
} 

Zum Beispiel können wir Funktionen zip:

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)) 
} 

Es stellt sich heraus, ein noch allgemeiner Ausdruck dieser Art zu sein. Im Allgemeinen Typkonstruktoren, die eine Implementierung dieser Schnittstelle lassen sind 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] 
} 

Eine Implementierung von zipWith wird dann nur dies:

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) 

Diese auf Funktionen jeder Stelligkeit verallgemeinert:

m.ap(m.ap(m.ap(m.map(f,a), b), c), d) 

Die Bibliothek Scalaz bietet anwendungsspezifische Instanzen für viele Datenstrukturen in der Standardbibliothek. Außerdem wird eine bequeme Syntax für ap bereitgestellt. In Scalaz heißt diese Funktion <*>:

def zipWith[F[_]:Applicative,A,B,C](f: A => B => C, a: F[A], b: F[B]) = 
    (a map f) <*> b 
+0

Danke. Ich muss so viel lernen. Das war sehr lehrreich. – wheaties

Verwandte Themen