Question

I want to convert multiple lists, each with a constant inner list size, that look like this:

    List(List(1, 2, 3), List(3, 4, 5))
    List(List(1, 2), List(3, 4))

to this:

    List((1, 2, 3), (3, 4, 5))
    List((1, 2), (3, 4))

So, if val q: List[List[Int]] = List(List(1, 2, 3), List(3, 4, 5), one could attempt to try the following:

    q.map(_.collect { case a :: b => (a,b) })

This gives you something of the following form, for the 3 element list example:

    List((1, List(2, 3)), (3, List(4, 5)))

I cannot flatten the tuples because they contain two types: Int and List[Int], so I cannot turn (1, List(2,3)) into (1,2,3) as desired.

So, how can I extend the flatten function to do this, or is there a better way to accomplish this in scala? Could scalaz help at all?

tl;dr: How can I turn inner lists of a list into tuples? (Possible generalized question: How to flatten polymorphic tupleNs?)

Was it helpful?

Solution

You can use implicits to do something of the like:

trait TupOps[T,I] {
  val size: Int
  def fromList(vals: List[I]): T
}

def list2tup[T,I](vals: List[List[I]])(implicit to: TupOps[T,I]) = {
  if (!vals.forall(_.size == to.size)) sys.error("wrong list size")
  else vals.map(to.fromList _)
}

implicit def tup2ops[I] = new TupOps[(I,I),I] {
  val size = 2
  def fromList(v: List[I]) = (v(0), v(1))
}

implicit def tup3ops[I] = new TupOps[(I,I,I),I] {
  val size = 3
  def fromList(v: List[I]) = (v(0), v(1), v(2))
}

Invoke like this:

list2tup[(Int,Int),Int](List(List(1,2),List(2,3)))

But this is not necessarily nicer, especially because you have to write the Int a second time, which is IMHO rather a syntax limitation, since you cannot give one type and tell the compiler to infer the other.

UPDATE

It looks almost nicer if you pass in the implicit explicitly:

list2tup(List(List(1,2),List(2,3)))(tup2ops)
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top