3
\$\begingroup\$

Let's say I have a bunch of Widget, where a Widget is

class Widget (sku: Int, label: String, name: String, description: String) 

And I have 2 sources of Widgets:

List[Widget] wInventory = getWidgetsInInventory()
List[Widget] wCatalog = getWidgetsFromCatalog()

I want to use the name & label from the Catalog to override any matching widget in Inventory. The match criteria is when sku == sku.
If the label is missing in the catalog, override with constant value of No Catalog Label instead of leaving label as is.
The wCatalog list may be empty. There may be no intersections at all, or both lists can contain the same set of sku's.

First draft of the code below. There must be a way to avoid running find twice, but because find returns Optional[Widget], it started looking messy with lots getOrElse. What's the cleanest way to do this?

case class MyWidget (sku: Int, label: String, name: String, description: String)

object HelloWorld {
  def main(args: Array[String]) {

    def setOverrideValues(inv : List[MyWidget], cat: List[MyWidget]) : List[MyWidget] = {
      inv.map (k => {
        val realName = cat.find( _.sku == k.sku).map(_.name)
        val realLabel = cat.find( _.sku == k.sku).map(_.label)

        k.copy(name = realName.getOrElse("No Catalog Label"), label=realLabel.getOrElse(k.label))
      })
    }

    val invItem1 = new MyWidget(sku=1, label="invLabel1", name="invName1", description="invDesc1");
    val invItem2 = new MyWidget(sku=2, label="invLabel2", name="invName2", description="invDesc2");
    val catItem1 = new MyWidget(sku=1, label="catLabel1", name="catName1", description="catDesc1");

    val wInventory = List(invItem1 , invItem2);
    val wCatalog = List(catItem1)

    val updated = setOverrideValues(wInventory, wCatalog)

    println("done")
  }
}
\$\endgroup\$
5
  • 1
    \$\begingroup\$ What is wCateogry? \$\endgroup\$
    – dcastro
    Aug 31, 2015 at 18:54
  • \$\begingroup\$ And, just to be sure, you don't want to override the description, right? Just the label and name? \$\endgroup\$
    – dcastro
    Aug 31, 2015 at 18:56
  • \$\begingroup\$ wCategory should be wCatalog. Yes, override only name & label, not description \$\endgroup\$ Aug 31, 2015 at 18:59
  • \$\begingroup\$ Then this is not your actual code, wCatalog.name will not compile, seeing as wCatalog is a list. \$\endgroup\$
    – dcastro
    Aug 31, 2015 at 19:00
  • \$\begingroup\$ Fixed code snippet to full working example. \$\endgroup\$ Aug 31, 2015 at 20:31

1 Answer 1

2
\$\begingroup\$

No need to run find twice, just run it once and store the result in a value of type Option[MyWidget].

You can then use Option#fold and pass in two functions: one to run when the option contains a matching widget, and another when no match was found.

def setOverrideValues(inv : List[MyWidget], cat: List[MyWidget]) : List[MyWidget] = {
  inv.map (k => {
    val wOpt = cat.find(_.sku == k.sku)

    wOpt.fold(ifEmpty = k.copy(name = "No Catalog Label")) {
      w => k.copy(name = w.name, label = w.label)
    }
  })
}

You could also use pattern matching

def setOverrideValues(inv : List[MyWidget], cat: List[MyWidget]) : List[MyWidget] = {
  for (k <- inv)
    yield cat.find(_.sku == k.sku) match {
      case Some(w) => k.copy(name = w.name, label = w.label)
      case _ => k.copy(name = "No Catalog Label")
    }
}

Both options would save you from repeated calls to find or getOrElse

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.