Scala: Creating a list of tuples from list elements sequentially

12,164

Solution 1

  1. += is a method on the ListBuffer l2 that accepts repeated parameters. That means when you do something like this:

    scala> var l2 = scala.collection.mutable.ListBuffer[(Int, Int)]()
    l2: scala.collection.mutable.ListBuffer[(Int, Int)] = ListBuffer()
    
    scala> l2 += (1, 2)
    <console>:9: error: type mismatch;
     found   : Int(1)
     required: (Int, Int)
                  l2 += (1, 2)
    

.. The compiler thinks you are trying to add multiple Ints to the ListBuffer, when you are trying to add a tuple. You need an extra set of parentheses.

 l1.zipWithIndex.slice(0,l1.length-1).foreach(x=> l2 += ((x._1,l1(x._2+1)) ))
  1. You can use sliding, which will create a "sliding window" across the collection to return a list of lists of a specific group size, with a step size of one by default:

    scala> List(0, 3, 6, 12, 14, 15, 16, 17).sliding(2)
               .map { case List(a, b) => (a, b) }.toList
    res10: List[(Int, Int)] = List((0,3), (3,6), (6,12), (12,14), (14,15), (15,16), (16,17))
    

Solution 2

besides the sliding, you could slide like following:

  val l1= List(0, 3, 6, 12, 14, 15, 16, 17)
  val l2 = l1.take(l1.size - 1).zip(l1.tail)

updated

   l1.zip(l1.tail) works.
Share:
12,164
rivu
Author by

rivu

Updated on June 08, 2022

Comments

  • rivu
    rivu almost 2 years

    I am very new to Scala so this question may be very naive.

    I have a list like this List[Int] = List(0, 3, 6, 12, 14, 15, 16, 17). I am trying to create a list like this [(0,3),(3,6),(6,12)..] and so on. So far this is what I have tried:

    val l1= List(0, 3, 6, 12, 14, 15, 16, 17)
    var l2=scala.collection.mutable.ListBuffer[(Int,Int)]()
    l1.zipWithIndex.slice(0,l1.length-1).foreach(x=>{val newval=(x._1,l1(x._2+1)); l2+=newval})
    

    Two questions here:

    1. If I don't use val newval, i.e. try to do l1.zipWithIndex.slice(0,l1.length-1).foreach(x=>l2+=(x._1,l1(x._2+1))), the compiler says: <console>:10: error: type mismatch; found : Int required: (Int, Int) l1.zipWithIndex.slice(0,l1.length-1).foreach(x=>l2+=(x._1,l1(x._2+1))). Why is that?
    2. What would a way to do it without the mutable listbuffer?
  • Silly Freak
    Silly Freak over 8 years
    size may be O(n), so I'd prefer dropRight, and then drop for symmetry
  • user1484819
    user1484819 over 8 years
    size is not O(n), but take is. I guess except head & tail, other methods on List are all O(n).
  • Michael Zajac
    Michael Zajac over 8 years
    l1.init would be more idiomatic than l1.take(l1.size - 1)
  • Silly Freak
    Silly Freak over 8 years
    @Paul you're right, I was mistaken about dropRight's implementation. I was basically thinking of Stream's implementation. Anyway, isn't the whole take part redundant as zip only takes commonly existing elements anyway? (even so, I agree that ensuring both lists have the same length is more readable)
  • Alexander Aleksandrovič Klimov
    Alexander Aleksandrovič Klimov over 8 years
    Yes, l1.zip(l1.tail) is all that's needed