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ą.
scala
functional-programming
list
zip
pr1001
źródło
źródło
Odpowiedzi:
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.
źródło
HList
s i tym podobne.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.
źródło
zipped
nie jest funkcjąList
.zipped
jest przestarzałe w Scali 2.13. w 2.13, dol1.lazyZip(l2).lazyZip(l3).toList
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) }
źródło
as zip bs zip cs zip ds map { case ((a,b),c)} map {case ((a,b),c,d)=>(a,b,c,d)}
as zip bs zip cs zip ds map {case (((a,b),c),d)=>(a,b,c,d) }
Tak, z zip3 .
źródło
transpose
Zró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))
źródło
def combineLists[A](ss:List[A]*) = { val sa = ss.reverse; (sa.head.map(List(_)) /: sa.tail)(_.zip(_).map(p=>p._2 :: p._1)) }
Scala traktuje wszystkich swoich różnych rozmiarach krotki jak różnych klas (
Tuple1
,Tuple2
,Tuple3
,Tuple4
, ...,Tuple22
), podczas gdy robią wszystko dziedziczą zProduct
cechą, ż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.
źródło
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
)źródło
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 typList[Tuple2[Int]]
. Gdyby miał trzy elementy, zwracany byłby typList[Tuple3[Int]]
i tak dalej.Możesz zwrócić
List[AnyRef]
, a nawetList[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)) }
źródło
c
zgadzasz się za
czy zb
? Jak byś to przedstawił, będąc w zgodzie z innymi?c
jest zgodne za
(tj. Zgodne z indeksem)?kolekcje produktów mają
flatZip
operację 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))
źródło
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"))((_, _, _, _, _, _, _, _, _, _, _, _))
źródło