Учитывая следующий список 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 списков с M элементами каждый и создать список из M TupleN.
Обновление 2: как оказалось, для моего конкретного варианта использования лучше иметь список списков, а не список кортежей, поэтому я принимаю ответ тыквы. Это также самый простой способ, поскольку в нем используется собственный метод.
scala
functional-programming
list
zip
pr1001
источник
источник
Ответы:
Я не верю, что можно сгенерировать список кортежей произвольного размера, но функция транспонирования делает именно то, что вам нужно, если вы не против получить вместо этого список списков.
источник
HList
s и т.п.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))
Для дальнейшего использования.
источник
zipped
это не функцияList
.zipped
устарела в Scala 2.13. в 2.13, dol1.lazyZip(l2).lazyZip(l3).toList
Таким образом, этот фрагмент кода не отвечает потребностям OP, и не только потому, что это поток четырехлетней давности, но он действительно отвечает на вопрос заголовка, и, возможно, кто-то даже может найти его полезным.
Чтобы заархивировать 3 коллекции:
as zip bs zip cs map { case ((a,b), c) => (a,b,c) }
источник
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) }
Да, с zip3 .
источник
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))
источник
def combineLists[A](ss:List[A]*) = { val sa = ss.reverse; (sa.head.map(List(_)) /: sa.tail)(_.zip(_).map(p=>p._2 :: p._1)) }
Scala рассматривает все разных размеров его кортежа разных классов (
Tuple1
,Tuple2
,Tuple3
,Tuple4
, ...,Tuple22
) в то время как они все наследуются отProduct
признака, что черта не несет достаточно информации , чтобы реально использовать значение данных из различных размеров кортежей если бы все они могли быть возвращены одной и той же функцией. (И дженерики scala также недостаточно мощны, чтобы справиться с этим случаем.)Лучше всего написать перегрузки функции zip для всех 22 размеров кортежей. Генератор кода, вероятно, поможет вам в этом.
источник
Если вы не хотите идти по пути аппликативного scalaz / cats / (вставьте сюда свою любимую функциональную библиотеку), то лучше всего подойдет сопоставление с образцом, хотя
(_, _)
синтаксис немного неудобен для вложенности, поэтому давайте изменим его:import scala.{Tuple2 => &} for (i1 & i2 & i3 & i4 <- list1 zip list2 zip list3 zip list4) yield (i1, i2, i3, i4)
&
Произвольный выбор здесь, все , что выглядит красиво инфикс должен сделать это. Однако во время проверки кода вы, скорее всего, удивитесь.Он также должен работать со всем, что вы можете
zip
(например,Future
с)источник
Я не верю, что это возможно без повторения. По одной простой причине: вы не можете определить тип возврата запрашиваемой функции.
Например, если ваш ввод был
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)) }
источник
c
в соответствии сa
или сb
? И как бы вы изобразили, что это соответствует другому?c
соответствуетa
(т.е. соответствует индексу)?product-collections имеет
flatZip
операцию до 22 arity.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))
источник
Со Скалазом:
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"))((_, _, _, _, _, _, _, _, _, _, _, _))
источник