Pair matching elements from two lists Here is a method that takes two lists (l1 and l2) and pairs up elements that "match". As you can see at the end of the code block these lists consist of matching elements but in different indexes. The method pairUp outputs matching elements paired up, and discards those without a pair.

I spent way too much time writing this method, and it feels clumsy and complex, not scala idiomatic.

How could I have done this simpler? and could I make it faster?

case class A(serial:Int) {
  def matches(b:B):Boolean = this.serial == b.serial
}
case class B(serial:Int)

import scala.annotation.tailrec
@tailrec def pairUp(
  list1:List[A],
  list2:List[B],
  i:Int=0,
  pairs:List[(A, B)]=List.empty[(A,B)]
):List[(A,B)] = {
  if (list1.isEmpty || list2.isEmpty) return pairs
  else {
    if (i == list2.length)  // this list1 element has no match
      return pairUp(
        list1.tail,         // so discard
        list2,
        0, // reset counter
        pairs)      
    else {
      if (list1.head matches list2.head) // these elements match
        return pairUp(
          list1.tail,
          list2.tail,
          0,
          pairs :+ ((list1.head, list2.head)))
      else
        return pairUp(
          list1,
          list2.tail :+ list2.head, // list2 element to back
          i + 1,
          pairs)
    }
  }
}

val l1 = List(0, 1, 2, 3, 4, 5).map(A(_))
val l2 = List(1, 3, 0, 2, 4).map(B(_))

val pairs = pairUp(l1, l2)
// List((A(0),B(0)), (A(1),B(1)), (A(2),B(2)), (A(3),B(3)), (A(4),B(4)))
println(pairs)
I am not an expert at scala, but this works for me

def pairUp2( list1: List[A], list2: List[B]): List[(A, B)] = {
    (for{
     a &lt;- list1
     b &lt;- list2
     if a.serial == b.serial
   } yield (a,b))
 }

 val pairs = pairUp2(l1, l2)
 pairs: List[(A, B)] = List((A(0),B(0)), (A(1),B(1)), (A(2),B(2)), (A(3),B(3)), (A(4),B(4)))


The for comprehension, takes each element of list1 and an element of list2 and yields a tuple only if the serial values match.