I am looking for a nice way to compare the elements of two Scala collections and produce a third collection based on a condition. I can sacrifice code appearance for performance.
Assuming the following:
case class Item(name: String, category: String, code: String, price: Int, freeItem: Option[Item])
val parentItems = Seq(
Item("name_1", "category_A", "code_A", 100, None),
Item("name_2", "category_B", "code_B", 100, None),
Item("name_3", "category_C", "code_C", 100, None)
)
val childItems = Seq(
Item("name_4", "category_A", "code_A", 100, None),
Item("name_5", "category_C", "code_C", 100, None)
)
def isChild(i1: Item, i2: Item): Boolean = {
i1.name != i2.name &&
i1.category == i2.category &&
i1.code == i2.code
}
val parentsWithChildren: Seq[Item] = (
for {
i1 <- parentItems;
i2 <- childItems
} yield {
if (isChild(i1, i2)) Some(i1.copy(freeItem = Some(i2.copy())))
else None
}).filter(_.isInstanceOf[Some[_]]).map(_.get)
The above snippet will produce the following result, which is the excpected:
Seq(
Item("name_1", "category_A", "code_A", 100,
Some(Item("name_4", "category_A", "company_A", 100, None))),
Item("name_3", "category_C", "code_C", 100,
Some(Item("name_5", "category_C", "company_C", 100, None)))
)
I know that the above code has loopholes but that's fine. What I am looking for is:
Is there any way I can avoid the if (isChild(i1, i2)) Some(i1.copy(freeItem = Some(i2.copy()))) else None
and as a result the .filter(_.isInstanceOf[Some[_]]).map(_.get)
? Would Partial Function be an option?
I am using nested loop here, I would do something like that in Java. Is there any other way to approach it? I thought I zip
at first but obviously doesn't work, by itself at least.
Thanks in advance!
I would be tempted to try something like this:
val parentsWithChildren: Seq[Item] =
for {
parent <- parentItems
child <- childItems if isChild(parent, child)
}
yield parent.copy(freeItem = Some(child))
Hope that helps!