Чи можу я створити більше двох списків разом у Scala?


93

Враховуючи такий список Scala:

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

Як я можу отримати:

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

Оскільки zip можна використовувати лише для поєднання двох Списків, я думаю, вам потрібно буде якось повторити / зменшити основний список. Не дивно, що наступне не працює:

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)

Будь-які пропозиції, як це зробити? Я думаю, що мені не вистачає дуже простого способу зробити це.

Оновлення: Я шукаю рішення, яке може взяти Список N Списків з М елементами в кожному та створити Список М TupleN.

Оновлення 2: Як виявляється, для мого конкретного випадку краще мати список списків, а не список кортежів, тому я приймаю відповідь гарбуза. Він також найпростіший, оскільки використовує власний метод.


можливий дублікат кількох послідовностей Zip
Сума

Безумовно варто відзначити: stackoverflow.com/questions/1683312 / ...
Venkat Sudheer Reddy Aedama

@VenkatSudheerReddyAedama Також запитував мене, через п’ять днів. ;-)
pr1001

Відповіді:


36

Я не вірю, що можливо сформувати список кортежів довільного розміру, але функція транспонування робить саме те, що вам потрібно, якщо ви не проти отримати список списків.


Дякую, це чудово працює! Розглядаючи свій конкретний випадок використання, я бачу, що перелік списків все одно буде кращим, оскільки мені потрібно скласти та зменшити різні підсписки.
pr1001

2
@JoshCason в найвужчому розумінні "більше двох", звичайно. Три насправді більше двох. Я інтерпретував питання в більш широкому розумінні "більше двох", маючи на увазі довільно багато. І в цьому випадку неможливо зробити те, що хоче запитання, якщо ви не потягнетеся до HLists та подібних.
copumpkin

посилання у відповіді недійсне
Рамеш Махарджан

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

Для подальшого використання.


32
Це чудово підходить для стиснення трьох списків. Сором це не працює більш ніж в три списки :(
Теона

2
Зверніть увагу, що спочатку це повинно бути в кортежі: zippedце не функція List.
Натаніель Форд

6
zippedзастаріло в Scala 2.13. в 2.13, робитиl1.lazyZip(l2).lazyZip(l3).toList
Сет Тісу

30

Отже, цей шматок коду не буде відповідати потребам OP, і не лише тому, що це чотирирічна нитка, але він відповідає на запитання щодо заголовка, і, можливо, комусь це може виявитися корисним.

Щоб зібрати 3 колекції:

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

зробити 4 колекції виглядає так:as zip bs zip cs zip ds map { case ((a,b),c)} map {case ((a,b),c,d)=>(a,b,c,d)}
Джеймс Тобін

1
@JamesTobin, u коротше доas zip bs zip cs zip ds map {case (((a,b),c),d)=>(a,b,c,d) }
постійно кодує

Приємно для списків різного типу.
FP Вільно

11

Так, із zip3 .


2
Дякую, але це працює лише з 3 списками. Я шукаю рішення, яке може взяти Список N Списків з М елементами в кожному і створити Список М TupleN.
pr1001

6

transposeробить трюк. Можливий алгоритм:

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

Наприклад:

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

Відповідь скорочується до розміру найкоротшого списку у введенні.

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

1
ця відповідь майже робить фокус, однак вона змінює елементи. Чи можете ви запропонувати вдосконалену версію, яка видає вихідні дані в очікуваному порядку? спасибі
fracca

Модифікована версія, яка зберігає порядок: 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 розглядає всі різних розмірів його кортежу різних класів ( Tuple1, Tuple2, Tuple3, Tuple4, ..., Tuple22) в той час як вони все успадковуються від Productознаки, що чорта не несе достатньо інформації , щоб реально використовувати значення даних з різних розмірів кортежів якби всі вони могли бути повернуті однією і тією ж функцією. (І дженерики Scala також недостатньо потужні, щоб розглянути цю справу.)

Ваша найкраща ставка - написати перевантаження функції zip для всіх 22 розмірів Tuple. У цьому вам, мабуть, допоможе генератор коду.


5

Якщо ви не хочете спускатися за додатковим маршрутом scalaz / cats / (вставте сюди улюблену функціональну бібліотеку), збіг шаблонів - це шлях, хоча (_, _)синтаксис трохи незручний при вкладенні, тому давайте змінимо його:

import scala.{Tuple2 => &}

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

Тут &є довільний вибір, і все, що виглядає приємно, має робити це. Однак ви, ймовірно, отримаєте кілька піднятих брів під час перегляду коду.

Він також повинен працювати з усім, що ви можете zip(наприклад, Futureз)


5

Я не вірю, що це можливо без повторення. З однієї простої причини: ви не можете визначити тип функції, яку ви вимагаєте, що повертається.

Наприклад, якщо ви ввели List(List(1,2), List(3,4)), тоді тип повернення буде List[Tuple2[Int]]. Якби він мав три елементи, тип повернення був би List[Tuple3[Int]]тощо.

Ви можете повернутися List[AnyRef], а то й навіть List[Product], а потім скласти купу справ, по одній для кожної умови.

Що стосується загального транспонування списку, це працює:

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

Це не буде працювати для списків довільного розміру. Наприклад: транспонування (Список (Список ("a", "b"), Список ("c")))
Venkat Sudheer Reddy Aedama

1
@VenkatSudheerReddyAedama Транспонування неповних матриць для мене не має сенсу. Візьмемо ваш приклад, якщо це cвідповідає aчи b? І як би ви уявили, що це відповідає іншому?
Даніель К. Собрал,

Домовились. Це неповна матриця. Я шукав щось на зразок zipAll. Скажімо, у моєму випадку cце відповідає a(тобто, відповідає індексу)?
Venkat Sudheer Reddy Aedama

2

product-collection має flatZipоперацію до 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

З 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"))

Більше 5:

// 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"))((_, _, _, _, _, _, _, _, _, _, _, _))
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.