Sunil Rajashekar Sunil Rajashekar -3 years ago 68
Scala Question

Zip non sequential list based on condition

I have a scenario where I to zip two lists in scala based on condition.
They might not be in sequence. What is the best way to do that?

I want to group DirectRetailCM and DirectRetailCM with same requestId as a tuple.

object Main extends App {
case class SalesDoc(val id: Int, val name: String, val requestId: String) {}
val list = List(
SalesDoc(1, "ILLEGAL", "1"),
SalesDoc(2, "DirectRetailCM", "1"),

SalesDoc(3, "DirectRetailOffsetInvoice", "2"),
SalesDoc(4, "DirectRetailCM", "2"),
SalesDoc(5, "OTHER", "2"),

SalesDoc(5, "DirectRetailCM", "LEFTOUT"),
SalesDoc(6, "ILLEGAL2", "4"),

SalesDoc(5, "OTHER", "3"),
SalesDoc(7, "DirectRetailOffsetInvoice", "4"),
SalesDoc(8, "DirectRetailCM", "4")
)

// I expect zip results of drOffsetInvoice and drCms as
List(
(SalesDoc(3, "DirectRetailOffsetInvoice", "2"), SalesDoc(4, "DirectRetailCM", "2")),
(SalesDoc(7, "DirectRetailOffsetInvoice", "4"), SalesDoc(8, "DirectRetailCM", "4"))
)
}


The initial approach that I can think of was


  • group directRetailCM - list.filter(e => e.name == "DirectRetailCM")

  • group DirectRetailOffsetInvoice - list.filter(e => e.name == "DirectRetailOffsetInvoice")

  • Zip both - But might not be in sequence

  • there could be rows which don't have counterparts



Can you please suggest any other approach that I need to consider?

Answer Source
// You don't need the val keyword for a case class
case class SalesDoc(id: Int, name: String, requestId: String)

val list = List(
  SalesDoc(1, "ILLEGAL", "1"),
  SalesDoc(2, "DirectRetailCM", "1"),

  SalesDoc(3, "DirectRetailOffsetInvoice", "2"),
  SalesDoc(4, "DirectRetailCM", "2"),
  SalesDoc(5, "OTHER", "2"),

  SalesDoc(5, "DirectRetailCM", "LEFTOUT"),
  SalesDoc(6, "ILLEGAL2", "4"),

  SalesDoc(5, "OTHER", "3"),
  SalesDoc(7, "DirectRetailOffsetInvoice", "4"),
  SalesDoc(8, "DirectRetailCM", "4")
)

// Find all of the DirectRetailOffsetInvoice items
val offsets = list.filter(_.name == "DirectRetailOffsetInvoice")

// Map over all of the DirectRetailOffsetInvoice items and see if there is matching DirectRetailCM item
val maybeMatched = offsets.map(offset => {
  val maybeCm = list.find(i => i.requestId == offset.requestId && i.name == "DirectRetailCM")

  // Return a tuple of type (SalesDoc, Option[SalesDoc])
  (offset, maybeCm)
})

// Map over the tuples and only take the ones where there was a match, and extract it from the Option to create a tuple of (SalesDoc, SalesDoc)
val output = maybeMatched.collect { case (s1, Some(s2)) => (s1, s2) }

output.foreach(println)
// (SalesDoc(3,DirectRetailOffsetInvoice,2),SalesDoc(4,DirectRetailCM,2))
// (SalesDoc(7,DirectRetailOffsetInvoice,4),SalesDoc(8,DirectRetailCM,4))
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download