Search code examples
scalajoindefault-valuecartesian-product

Scala - conditional product/join of two arrays with default values using for comprehensions


I have two Sequences, say:

val first = Array("B", "L", "T")      
val second = Array("T70", "B25", "B80", "A50", "M100", "B50")   

How do I get a product such that elements of the first array are joined with each element of the second array which startsWith the former and also yield a default empty result when no element in the second array meets the condition.

Effectively to get an Output:

expectedProductArray = Array("B-B25", "B-B80", "B-B50", "L-Default", "T-T70")

I tried doing,

  val myProductArray: Array[String] = for {
    f <- first
    s <- second if s.startsWith(f)
  } yield s"""$f-$s"""

and i get:

myProductArray = Array("B-B25", "B-B80", "B-B50", "T-T70")

Is there an Idiomatic way of adding a default value for values in first sequence not having a corresponding value in the second sequence with the given criteria? Appreciate your thoughts.


Solution

  • Here's one approach by making array second a Map and looking up the Map for elements in array first with getOrElse:

    val first = Array("B", "L", "T")      
    val second = Array("T70", "B25", "B80", "A50", "M100", "B50")  
    
    val m = second.groupBy(_(0).toString)
    // m: scala.collection.immutable.Map[String,Array[String]] =
    //   Map(M -> Array(M100), A -> Array(A50), B -> Array(B25, B80, B50), T -> Array(T70))
    
    first.flatMap(x => m.getOrElse(x, Array("Default")).map(x + "-" + _))
    // res1: Array[String] = Array(B-B25, B-B80, B-B50, L-Default, T-T70)
    

    In case you prefer using for-comprehension:

    for {
      x <- first
      y <- m.getOrElse(x, Array("Default"))
    } yield s"$x-$y"