Czy w Scali mogę spakować więcej niż dwie listy?


94

Biorąc pod uwagę następującą listę Scala:

val l = List(List("a1", "b1", "c1"), List("a2", "b2", "c2"), List("a3", "b3", "c3"))

Jak mogę zdobyć:

List(("a1", "a2", "a3"), ("b1", "b2", "b3"), ("c1", "c2", "c3"))

Ponieważ zip może być używany tylko do łączenia dwóch list, myślę, że musiałbyś jakoś powtórzyć / zmniejszyć główną listę. Nic dziwnego, że poniższe rozwiązania nie działają:

scala> l reduceLeft ((a, b) => a zip b)
<console>:6: error: type mismatch;
 found   : List[(String, String)]
 required: List[String]
       l reduceLeft ((a, b) => a zip b)

Jakieś sugestie, jak to zrobić? Myślę, że brakuje mi bardzo prostego sposobu, aby to zrobić.

Aktualizacja: Szukam rozwiązania, które może wziąć Listę N List z M elementami każdy i utworzyć Listę M TupleNs.

Aktualizacja 2: Jak się okazuje, dla mojego konkretnego przypadku lepiej jest mieć listę list, a nie listę krotek, więc akceptuję odpowiedź dyni. Jest też najprostszy, ponieważ wykorzystuje metodę natywną.


możliwy duplikat wielu sekwencji Zip
Suma


@VenkatSudheerReddyAedama Również zadane przeze mnie pięć dni później. ;-)
pr1001 22.07.15

Odpowiedzi:


36

Nie sądzę, aby można było wygenerować listę krotek o dowolnym rozmiarze, ale funkcja transpozycji robi dokładnie to, czego potrzebujesz, jeśli nie masz nic przeciwko otrzymywaniu listy list.


Dzięki, to działa idealnie! Kiedy przechodzę do mojego konkretnego przypadku użycia, widzę, że lista list i tak byłaby lepsza, ponieważ muszę zmapować i zredukować różne listy podrzędne.
pr1001

2
@JoshCason w najwęższym znaczeniu „więcej niż dwa”, oczywiście. Trzy to rzeczywiście więcej niż dwa. Zinterpretowałem to pytanie w szerszym znaczeniu „więcej niż dwóch”, czyli arbitralnie wielu. W takim przypadku nie można zrobić tego, czego chce pytanie, chyba że sięgniesz po HLists i tym podobne.
copumpkin

link w odpowiedzi jest uszkodzony, nowy link to scala-lang.org/api/2.12.1/scala/…
Ramesh Maharjan

216
scala> (List(1,2,3),List(4,5,6),List(7,8,9)).zipped.toList
res0: List[(Int, Int, Int)] = List((1,4,7), (2,5,8), (3,6,9))

Dla przyszłego odniesienia.


32
To jest świetne do spakowania trzech list. Szkoda, że ​​to nie działa na więcej niż trzech listach :(
theon

2
Zwróć uwagę, że najpierw musi to być krotka: zippednie jest funkcją List.
Nathaniel Ford

6
zippedjest przestarzałe w Scali 2.13. w 2.13, dol1.lazyZip(l2).lazyZip(l3).toList
Seth Tisue

30

Więc ten fragment kodu nie będzie odpowiadał na potrzeby OP, i to nie tylko dlatego, że jest to wątek czteroletni, ale odpowiada na tytułowe pytanie i być może ktoś może nawet uznać go za przydatny.

Aby spakować 3 kolekcje:

as zip bs zip cs map { 
  case ((a,b), c) => (a,b,c)
}

do zrobienia 4 kolekcji wygląda następująco:as zip bs zip cs zip ds map { case ((a,b),c)} map {case ((a,b),c,d)=>(a,b,c,d)}
James Tobin

1
@JamesTobin, u as zip bs zip cs zip ds map {case (((a,b),c),d)=>(a,b,c,d) }
shorten to

Przyjemne dla list różnego typu.
FP Freely

11

Tak, z zip3 .


2
Dzięki, ale działa tylko z 3 listami. Szukam rozwiązania, które może wziąć Listę N List z M elementami każdy i utworzyć Listę M TupleNs.
pr1001

6

transposeZrób sztuczkę. Możliwym algorytmem jest:

def combineLists[A](ss:List[A]*) = {
    val sa = ss.reverse;
    (sa.head.map(List(_)) /: sa.tail)(_.zip(_).map(p=>p._2 :: p._1))
}

Na przykład:

combineLists(List(1, 2, 3), List(10,20), List(100, 200, 300))
// => List[List[Int]] = List(List(1, 10, 100), List(2, 20, 200))

Odpowiedź jest obcinana do rozmiaru najkrótszej listy w danych wejściowych.

combineLists(List(1, 2, 3), List(10,20))
// => List[List[Int]] = List(List(1, 10), List(2, 20))

1
ta odpowiedź prawie załatwia sprawę, jednak odwraca elementy. Czy możesz zaproponować ulepszoną wersję, która generuje dane wyjściowe w oczekiwanej kolejności? dzięki
fracca

Zmodyfikowana wersja, która zachowuje kolejność: def combineLists[A](ss:List[A]*) = { val sa = ss.reverse; (sa.head.map(List(_)) /: sa.tail)(_.zip(_).map(p=>p._2 :: p._1)) }
rogermenezes

5

Scala traktuje wszystkich swoich różnych rozmiarach krotki jak różnych klas ( Tuple1, Tuple2, Tuple3, Tuple4, ..., Tuple22), podczas gdy robią wszystko dziedziczą z Productcechą, że cecha nie prowadzi wystarczająco dużo informacji, aby rzeczywiście skorzystać z wartości danych z różnych rozmiarów krotek gdyby wszystkie mogły zostać zwrócone przez tę samą funkcję. (A typy generyczne Scala również nie są wystarczająco wydajne, aby obsłużyć ten przypadek).

Najlepszym rozwiązaniem jest zapisanie przeciążeń funkcji zip dla wszystkich 22 rozmiarów krotki. Prawdopodobnie pomoże Ci w tym generator kodu.


5

Jeśli nie chcesz przechodzić przez ścieżkę aplikacyjną scalaz / cats / (wstaw tutaj swoją ulubioną bibliotekę funkcjonalną), najlepszym rozwiązaniem jest dopasowanie wzorców, chociaż (_, _)składnia jest nieco niezręczna przy zagnieżdżaniu, więc zmieńmy to:

import scala.{Tuple2 => &}

for (i1 & i2 & i3 & i4 <- list1 zip list2 zip list3 zip list4) yield (i1, i2, i3, i4)

Wybór &jest tutaj arbitralny, wszystko, co wygląda ładnie wrostek, powinno to zrobić. Jednak prawdopodobnie podczas przeglądu kodu pojawi się kilka uniesionych brwi.

Powinien również działać ze wszystkim, co możesz zip(np. Future)


5

Nie wierzę, że jest to możliwe bez powtarzania się. Z jednego prostego powodu: nie możesz zdefiniować zwracanego typu funkcji, o którą prosisz.

Na przykład, jeśli dane wejściowe to List(List(1,2), List(3,4)), to zwracany byłby typ List[Tuple2[Int]]. Gdyby miał trzy elementy, zwracany byłby typ List[Tuple3[Int]]i tak dalej.

Możesz zwrócić List[AnyRef], a nawet List[Product]zrobić kilka przypadków, po jednym dla każdego warunku.

Jeśli chodzi o ogólną transpozycję listy, działa to:

def transpose[T](l: List[List[T]]): List[List[T]] = l match {
  case Nil => Nil
  case Nil :: _ => Nil
  case _ => (l map (_.head)) :: transpose(l map (_.tail))
}

To nie zadziała w przypadku list o dowolnej wielkości. Na przykład: transpose (List (List ("a", "b"), List ("c")))
Venkat Sudheer Reddy Aedama

1
@VenkatSudheerReddyAedama Transpozycja niekompletnych macierzy nie ma dla mnie sensu. Aby wziąć twój przykład, jeśli czgadzasz się z aczy z b? Jak byś to przedstawił, będąc w zgodzie z innymi?
Daniel C. Sobral

Zgoda. To niekompletna macierz. Szukałem czegoś na wzór zipAll. Powiedzmy, że w moim przypadku cjest zgodne z a(tj. Zgodne z indeksem)?
Venkat Sudheer Reddy Aedama

2

kolekcje produktów mają flatZipoperację do 22.

scala> List(1,2,3) flatZip Seq("a","b","c") flatZip Vector(1.0,2.0,3.0) flatZip Seq(9,8,7)
res1: com.github.marklister.collections.immutable.CollSeq4[Int,String,Double,Int] = 
CollSeq((1,a,1.0,9),
        (2,b,2.0,8),
        (3,c,3.0,7))

0

Ze Scalaz:

import scalaz.Zip
import scalaz.std.list._

// Zip 3
Zip[List].ap.tuple3(List("a1", "b1"),
                    List("a2", "b2"),
                    List("a3", "b3"))

// Zip 4
Zip[List].ap.tuple4(List("a1", "b1"),
                    List("a2", "b2"),
                    List("a3", "b3"),
                    List("a4", "b4"))

// Zip 5
Zip[List].ap.tuple5(List("a1", "b1"),
                    List("a2", "b2"),
                    List("a3", "b3"),
                    List("a4", "b4"),
                    List("a5", "b5"))

Powyżej 5 lat:

// Zip 6
Zip[List].ap.apply6(List("a1", "b1"),
                    List("a2", "b2"),
                    List("a3", "b3"),
                    List("a4", "b4"),
                    List("a5", "b5"),
                    List("a6", "b6"))((_, _, _, _, _, _))

// Zip 7
Zip[List].ap.apply7(List("a1", "b1"),
                    List("a2", "b2"),
                    List("a3", "b3"),
                    List("a4", "b4"),
                    List("a5", "b5"),
                    List("a6", "b6"),
                    List("a7", "b7"))((_, _, _, _, _, _, _))

...

// Zip 12
Zip[List].ap.apply12(List("a1", "b1"),
                     List("a2", "b2"),
                     List("a3", "b3"),
                     List("a4", "b4"),
                     List("a5", "b5"),
                     List("a6", "b6"),
                     List("a7", "b7"),
                     List("a8", "b8"),
                     List("a9", "b9"),
                     List("a10", "b10"),
                     List("a11", "b11"),
                     List("a12", "b12"))((_, _, _, _, _, _, _, _, _, _, _, _))
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.