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.
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.
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.
In Scala, We can use for-loop with collections like List etc. It provides an efficient way to iterate over the collections.
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
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With