αƞjiβ
αƞjiβ

Reputation: 3246

Break out of double foreach in Scala

I have to return true or false based on field value in inner set item. My loops is as follow

myChoice.category.foreach(category => {
  category.flavours.foreach(flavour=> {
    if (flavour.available) true
  })
})
false

It shoudld break and return true as soon as I have true on available but its returning false all the time. Any suggestion?

Upvotes: 1

Views: 1428

Answers (3)

Alexey Romanov
Alexey Romanov

Reputation: 170713

Disclaimer: the below solution is provided for completeness, but jwvh's answer should be preferred for this case and generally speaking there are better alternatives. In particular, note that return from inside a lambda is implemented using exceptions, so 1) it may perform much worse than normal method calls; 2) if you are careless you can accidentally catch it.

If this is the last thing you need to do in the method, you can just use return:

myChoice.category.foreach(category => {
  category.flavours.foreach(flavour=> {
    if (flavour.available) return true
  })
})
false

If it isn't, you can extract a method (including a local one):

def foo = {
  ...

  val myChoice = ...

  def hasAvailableFlavorsMethod() = {
    myChoice.category.foreach(category => {
      category.flavours.foreach(flavour=> {
        if (flavour.available) return true
      })
    })
    false
  }

  val hasAvailableFlavors = hasAvailableFlavorsMethod()

  ...
}

Upvotes: 0

Mshnik
Mshnik

Reputation: 7032

Scala doesn't have continue or break. Because it is a fully functional language, every expression (including a loop) must have a value. Moreover, it tries to break out of the imperative style of initializing variables and mutating them over the course of a loop. Instead, scala encourages you to use a functional style, i.e. use methods that apply to data structures as a whole to transform/search for the desired result.

For your case, you're clearly looking to see if any of the flavors have their available field set to true. Thus you could flatMap the whole nested collection to a List of Boolean, and take the or of the whole collection:

val anyAvaliable = myChoice.category.flatMap(a => a.flavours).reduce( (flavour1,flavour2) => flavour1.available || flavour2.available)

jwvh's solution is even more concise. There are many ways of accomplishing essentially the same thing. Don't fight the language, have it fight for you!

Upvotes: 3

jwvh
jwvh

Reputation: 51271

I don't have your dataset to work with, but perhaps this might do it.

myChoice.category.exists(_.flavours.exists(_.available))

Upvotes: 6

Related Questions