Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scala return a value from a for cycle

I have the following piece of code

def my_function(condition: Int=>Boolean): Int = {
  for (i <- 0 to 10)
    if (condition(i)) return i

  return -1
}

The code is simple: if some condition is met for a number between 1 and 10, return the number, else return invalid result (-1).

It works perfectly fine, but it violates some of the functional programming principles, because of the return in the for cycle. How can I refactor this method (I got unit tests, too) and remove the return statements. I suppose that I must use yield, but it seems to produce list, I just need one value.

like image 474
Kiril Kirilov Avatar asked Sep 26 '12 10:09

Kiril Kirilov


People also ask

Which keyword is used to return value from for loop in Scala?

In Scala, the loop's return value is stored in a variable or may return through a function. To do this, you should prefix the body of the 'for' expression with the keyword yield.

What does :+ mean in Scala?

On Scala Collections there is usually :+ and +: . Both add an element to the collection. :+ appends +: prepends. A good reminder is, : is where the Collection goes. There is as well colA ++: colB to concat collections, where the : side collection determines the resulting type.

Can we use for loop in Scala?

In Scala, We can use for-loop with collections like List etc. It provides an efficient way to iterate over the collections.


2 Answers

This is the functional translation of your code:

def my_function(condition: Int => Boolean): Int = {
  (0 to 10).find(i => condition(i)).getOrElse(-1)
}

Or more succinctly as:

def my_function(condition: Int => Boolean): Int = {
  (0 to 10).find(condition).getOrElse(-1)
}

I've used the find method which takes, as an argument, a function that produces a Boolean. The find method returns the first item in the collection that satisfies the condition. It returns the item as an Option so that if there is no satisfying item, then the result will be None. The getOrElse method of Option will return the found result if there is one, and return -1 if there isn't.

However, you should not use "error codes" like returning -1 in Scala programming. They are bad practice. Instead your should throw an exception or return an Option[Int] such that returning None indicates no value was found. The right way to do this would be something like:

def my_function(condition: Int => Boolean): Option[Int] = {
  (0 to 10).find(condition)
}

println(my_function(_ > 5))   // Some(6)
println(my_function(_ > 11))  // None
like image 118
dhg Avatar answered Sep 20 '22 15:09

dhg


You can use the native collection method

def my_function(condition: Int => Boolean): Int =
  (1 to 10).find(condition).getOrElse(-1)

Usually in scala you should avoid "error code" using an Option return

def my_function(condition: Int => Boolean) : Option[Int] =
  (1 to 10).find(condition)

Similarly you can use a for-yield comprehension

def my_function(condition: Int => Boolean): Int =
  (for (i <- 1 to 10; if condition(i)) yield i).headOption.getOrElse(-1)

or with Option

def my_function(condition: Int => Boolean): Int =
  (for (i <- 1 to 10; if condition(i)) yield i).headOption

or use recursion as @Jan suggestion

like image 30
Federico Dal Maso Avatar answered Sep 23 '22 15:09

Federico Dal Maso