Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Combining multiple Lists of arbitrary length

I am looking for an approach to join multiple Lists in the following manner:

ListA a b c
ListB 1 2 3 4
ListC + # * § %
..
..
..

Resulting List: a 1 + b 2 # c 3 * 4 § %

In Words: The elements in sequential order, starting at first list combined into the resulting list. An arbitrary amount of input lists could be there varying in length.

I used multiple approaches with variants of zip, sliding iterators but none worked and especially took care of varying list lengths. There has to be an elegant way in scala ;)

like image 773
Th 00 mÄ s Avatar asked Sep 30 '13 14:09

Th 00 mÄ s


2 Answers

val lists = List(ListA, ListB, ListC)

lists.flatMap(_.zipWithIndex).sortBy(_._2).map(_._1)

It's pretty self-explanatory. It just zips each value with its position on its respective list, sorts by index, then pulls the values back out.

like image 194
Luigi Plinge Avatar answered Oct 05 '22 22:10

Luigi Plinge


Here's how I would do it:

class ListTests extends FunSuite {
  test("The three lists from his example") {
    val l1 = List("a", "b", "c")
    val l2 = List(1, 2, 3, 4)
    val l3 = List("+", "#", "*", "§", "%")

    // All lists together
    val l = List(l1, l2, l3)

    // Max length of a list (to pad the shorter ones)
    val maxLen = l.map(_.size).max

    // Wrap the elements in Option and pad with None
    val padded = l.map { list => list.map(Some(_)) ++ Stream.continually(None).take(maxLen - list.size) }

    // Transpose 
    val trans = padded.transpose

    // Flatten the lists then flatten the options
    val result = trans.flatten.flatten

    // Viola 
    assert(List("a", 1, "+", "b", 2, "#", "c", 3, "*", 4, "§", "%") === result)
  }
}
like image 43
joescii Avatar answered Oct 05 '22 21:10

joescii