Passing a function to another function as statement - scala

I want to write a function which will return true if given an even number as an argument or false otherwise. additionally, write a function that will filter a list of numbers returning just the even numbers. All done using Scala functional programming. This is what I have:
def isEven(n:Int): Boolean = n % 2 == 0
println(isEven(4))
val filterEven = ( xs :List[Int] ) => {
for( x <- xs; if x % 2 == 0 ) yield x
}
println(filterEven(List(3,2,4,5,6,22,91)))
My question is, how can I pass the first function "isEven" to to the "filterEven" function in order to replace the "if-statement"?
Regards.

You can pass isEven as a parameter to xs.filter
def filterEven(xs: List[Int]) = xs.filter(isEven)
This is functionally equivalent to:
def filterEven(xs: List[Int]) = for { x <- xs if isEven(x) } yield x

First you give it a name when it is passed in.
val filterEven = (xs :List[Int], filterFunc: Int => Boolean) => {
Then you invoke it under its new name.
for(x <- xs; if filterFunc(x)) yield x
Note that now filterEven is not a good name for your function. The parameter passed in as filterFunc will determine whether you filter even, or odd, or less than 100, or .....

Related

scala: How to convert an anonymous function to val

I'm a beginner learning scala and looking into anon functions and vals.
I'm not able to convert {case e if e % 2 == 0 => e} to a Val. I've tried different syntax (sample shown below) to no avail. There is no real purpose for converting to val; just trying to get a deeper understanding.
package exercises.functions
object CollectVal extends App {
println(List(1,2,3,4,5).collect{case e if e % 2 == 0 => e})
// val onlyEvens: Int = e:Int => Int = e if (e % 2 == 0 ) => e
// val onlyEvens = e:Int = {case e if e % 2 == 0 => e}
println(List(1,2,3,4,5).collect{onlyEvens})
}
Any help is appreciated
Thanks!
What you need to express is a function. So the type of the variable in this case is:
val onlyEvens: Int => Int
In particular, collect accept a PartialFunction (i.e. a function that is not defined for some input value). So it is more correct to write:
val onlyEvens: PartialFunction[Int, Int] = { case e if e % 2 == 0 => e }
Finally, you can pass this val in the collect method:
List(1,2,3,4,5).collect(onlyEvens)
Scastie
Syntax to assign an anonymous function to a val would be something like this (note parentheses around e):
val x: Int => Int = (e) => if (e % 2 == 0) e else ???
or equivalently, but a bit shorter: val x = (e: Int) => if (e % 2 == 0) e else ???
But it looks like what you are looking for is a partial function rather than just a function. PartialFunction is like a regular function, but it is only defined for some of the possible values of its parameter. In your case, you want it only defined for even numbers:
val x = PartialFunction[Int, Int] { case e if e % 2 == 0 => e }
The { case foo => bar } shorthand works for partial functions but not regular functions, that's why you were having problems trying to define a function that way. This creates a PartialFunction that is defined for all integer values that match one of the case clauses, and not for any others.

Confused about behavior on Option between single-level and nested for comprehension

I'm new to Scala so please bear with me.
I'm confused about the behaviors below:
val l = List(Option(1))
for (i <- l; x <- i) yield x //Example 1: gives me List(1)
for(x <- Option(1)) yield x //Example 2: gives me Some(1)
Why doesn't the second for comprehension give me 1 instead? Because that would look more consistent to me, intuitively, since the second for comprehension in the first example x <- i looks like it should behave exactly the same way as the second example, as the second example basically has extracted the option out of the list to begin with.
Simply put, for comprehension wraps into the type that was used the first time.
for (x <- Option(1)) yield x // Returns Option
for (x <- List(1)) yield x // Returns List
for (x <- Array(1)) yield x // Returns Array
This:
for (i <- List(Some(1)); x <- i) yield x
Desugares into this:
List(Some(1)).flatMap { case i => i.map { case x => x } }
flatMap of List returns List[T], that's why it behaves like that

Scala: transform a collection, yielding 0..many elements on each iteration

Given a collection in Scala, I'd like to traverse this collection and for each object I'd like to emit (yield) from 0 to multiple elements that should be joined together into a new collection.
For example, I expect something like this:
val input = Range(0, 15)
val output = input.somefancymapfunction((x) => {
if (x % 3 == 0)
yield(s"${x}/3")
if (x % 5 == 0)
yield(s"${x}/5")
})
to build an output collection that will contain
(0/3, 0/5, 3/3, 5/5, 6/3, 9/3, 10/5, 12/3)
Basically, I want a superset of what filter (1 → 0..1) and map (1 → 1) allows to do: mapping (1 → 0..n).
Solutions I've tried
Imperative solutions
Obviously, it's possible to do so in non-functional maneer, like:
var output = mutable.ListBuffer()
input.foreach((x) => {
if (x % 3 == 0)
output += s"${x}/3"
if (x % 5 == 0)
output += s"${x}/5"
})
Flatmap solutions
I know of flatMap, but it again, either:
1) becomes really ugly if we're talking about arbitrary number of output elements:
val output = input.flatMap((x) => {
val v1 = if (x % 3 == 0) {
Some(s"${x}/3")
} else {
None
}
val v2 = if (x % 5 == 0) {
Some(s"${x}/5")
} else {
None
}
List(v1, v2).flatten
})
2) requires usage of mutable collections inside it:
val output = input.flatMap((x) => {
val r = ListBuffer[String]()
if (x % 3 == 0)
r += s"${x}/3"
if (x % 5 == 0)
r += s"${x}/5"
r
})
which is actually even worse that using mutable collection from the very beginning, or
3) requires major logic overhaul:
val output = input.flatMap((x) => {
if (x % 3 == 0) {
if (x % 5 == 0) {
List(s"${x}/3", s"${x}/5")
} else {
List(s"${x}/3")
}
} else if (x % 5 == 0) {
List(s"${x}/5")
} else {
List()
}
})
which is, IMHO, also looks ugly and requires duplicating the generating code.
Roll-your-own-map-function
Last, but not least, I can roll my own function of that kind:
def myMultiOutputMap[T, R](coll: TraversableOnce[T], func: (T, ListBuffer[R]) => Unit): List[R] = {
val out = ListBuffer[R]()
coll.foreach((x) => func.apply(x, out))
out.toList
}
which can be used almost like I want:
val output = myMultiOutputMap[Int, String](input, (x, out) => {
if (x % 3 == 0)
out += s"${x}/3"
if (x % 5 == 0)
out += s"${x}/5"
})
Am I really overlooking something and there's no such functionality in standard Scala collection libraries?
Similar questions
This question bears some similarity to Can I yield or map one element into many in Scala? — but that question discusses 1 element → 3 elements mapping, and I want 1 element → arbitrary number of elements mapping.
Final note
Please note that this is not the question about division / divisors, such conditions are included purely for illustrative purposes.
Rather than having a separate case for each divisor, put them in a container and iterate over them in a for comprehension:
val output = for {
n <- input
d <- Seq(3, 5)
if n % d == 0
} yield s"$n/$d"
Or equivalently in a collect nested in a flatMap:
val output = input.flatMap { n =>
Seq(3, 5).collect {
case d if n % d == 0 => s"$n/$d"
}
}
In the more general case where the different cases may have different logic, you can put each case in a separate partial function and iterate over the partial functions:
val output = for {
n <- input
f <- Seq[PartialFunction[Int, String]](
{case x if x % 3 == 0 => s"$x/3"},
{case x if x % 5 == 0 => s"$x/5"})
if f.isDefinedAt(n)
} yield f(n)
You can also use some functional library (e.g. scalaz) to express this:
import scalaz._, Scalaz._
def divisibleBy(byWhat: Int)(what: Int): List[String] =
(what % byWhat == 0).option(s"$what/$byWhat").toList
(0 to 15) flatMap (divisibleBy(3) _ |+| divisibleBy(5))
This uses the semigroup append operation |+|. For Lists this operation means a simple list concatenation. So for functions Int => List[String], this append operation will produce a function that runs both functions and appends their results.
If you have complex computation, during which you should sometimes add some elements to operation global accumulator, you can use popular approach named Writer Monad
Preparation in scala is somewhat bulky but results are extremely composable thanks to Monad interface
import scalaz.Writer
import scalaz.syntax.writer._
import scalaz.syntax.monad._
import scalaz.std.vector._
import scalaz.syntax.traverse._
type Messages[T] = Writer[Vector[String], T]
def yieldW(a: String): Messages[Unit] = Vector(a).tell
val output = Vector.range(0, 15).traverse { n =>
yieldW(s"$n / 3").whenM(n % 3 == 0) >>
yieldW(s"$n / 5").whenM(n % 5 == 0)
}.run._1
Here is my proposition for a custom function, might be better with pimp my library pattern
def fancyMap[A, B](list: TraversableOnce[A])(fs: (A => Boolean, A => B)*) = {
def valuesForElement(elem: A) = fs collect { case (predicate, mapper) if predicate(elem) => mapper(elem) }
list flatMap valuesForElement
}
fancyMap[Int, String](0 to 15)((_ % 3 == 0, _ + "/3"), (_ % 5 == 0, _ + "/5"))
You can try collect:
val input = Range(0,15)
val output = input.flatMap { x =>
List(3,5) collect { case n if (x%n == 0) => s"${x}/${n}" }
}
System.out.println(output)
I would us a fold:
val input = Range(0, 15)
val output = input.foldLeft(List[String]()) {
case (acc, value) =>
val acc1 = if (value % 3 == 0) s"$value/3" :: acc else acc
val acc2 = if (value % 5 == 0) s"$value/5" :: acc1 else acc1
acc2
}.reverse
output contains
List(0/3, 0/5, 3/3, 5/5, 6/3, 9/3, 10/5, 12/3)
A fold takes an accumumlator (acc), a collection, and a function. The function is called with the initial value of the accumumator, in this case an empty List[String], and each value of the collection. The function should return an updated collection.
On each iteration, we take the growing accumulator and, if the inside if statements are true, prepend the calculation to the new accumulator. The function finally returns the updated accumulator.
When the fold is done, it returns the final accumulator, but unfortunately, it is in reverse order. We simply reverse the accumulator with .reverse.
There is a nice paper on folds: A tutorial on the universality and expressiveness of fold, by Graham Hutton.

How to combine filter and map in Scala?

I have List[Int] in Scala. The List is List(1,2,3,4,5,6,7,8,9,10). I want to filter the list so that it only has even numbers. And I want to multiply the numbers with 2.
Is it possible?
As I state in my comment, collect should do what you want:
list.collect{
case x if x % 2 == 0 => x*2
}
The collect method allows you to both specify a criteria on the matching elements (filter) and modify the values that match (map)
And as #TravisBrown suggested, you can use flatMap as well, especially in situations where the condition is more complex and not suitable as a guard condition. Something like this for your example:
list.flatMap{
case x if x % 2 == 0 => Some(x*2)
case x => None
}
A for comprehension (which internally unfolds into a combination of map and withFilter) as follows,
for (x <- xs if x % 2 == 0) yield x*2
Namely
xs.withFilter(x => x % 2 == 0).map(x => x*2)
As #cmbaxter said, collect suits your need perfectly. The other nice thing about collect is that it figures out resulting type in case you're filtering by class:
scala> trait X
// defined trait X
scala> class Foo extends X
// defined class Foo
scala> class Bar extends X
// defined class Bar
scala> val xs = List(new Foo, new Bar, new Foo, new Bar)
// xs: List[X] = List(Foo#4cfa8227, Bar#78226c36, Foo#3f685162, Bar#11f406f8)
scala> xs.collect { case x: Foo => x }
// res1: List[Foo] = List(Foo#4cfa8227, Foo#3f685162)
On par, filter can't be that smart (see List[Foo] vs List[X]):
scala> xs.filter { case x: Foo => true; case _ => false }
// res3: List[X] = List(Foo#4cfa8227, Foo#3f685162)
This should do the work for you:
Filter first when the condition is p % 2 == 0 (for getting only even numbers).
And then use map to multiply those even numbers by 2.
var myList = List(1,2,3,4,5,6,7,8,9,10).filter(p => p % 2 == 0).map(p => {p*2})
I tend to like the filter approach.
val list1 = List(1,2,3,4,5,6,7,8,9,10)
list1.filter(x => x%2 == 0).map(_*2)
How about a good old fashioned fold?
xs.foldLeft(List[Y]()) { (ys, x) =>
val z = calculateSomethingOnX(x)
if (someConditionOnZ(z))
Y(x, z) :: ys
else
ys
}

Converting a sequence of map operations to a for-comprehension

I read in Programming in Scala section 23.5 that map, flatMap and filter operations can always be converted into for-comprehensions and vice-versa.
We're given the following equivalence:
def map[A, B](xs: List[A], f: A => B): List[B] =
for (x <- xs) yield f(x)
I have a value calculated from a series of map operations:
val r = (1 to 100).map{ i => (1 to 100).map{i % _ == 0} }
.map{ _.foldLeft(false)(_^_) }
.map{ case true => "open"; case _ => "closed" }
I'm wondering what this would look like as a for-comprehension. How do I translate it?
(If it's helpful, in words this is:
take integers from 1 to 100
for each, create a list of 100 boolean values
fold each list with an XOR operator, back into a boolean
yield a list of 100 Strings "open" or "closed" depending on the boolean
I imagine there is a standard way to translate map operations and the details of the actual functions in them is not important. I could be wrong though.)
Is this the kind of translation you're looking for?
for (i <- 1 to 100;
val x = (1 to 100).map(i % _ == 0);
val y = x.foldLeft(false)(_^_);
val z = y match { case true => "open"; case _ => "closed" })
yield z
If desired, the map in the definition of x could also be translated to an "inner" for-comprehension.
In retrospect, a series of chained map calls is sort of trivial, in that you could equivalently call map once with composed functions:
s.map(f).map(g).map(h) == s.map(f andThen g andThen h)
I find for-comprehensions to be a bigger win when flatMap and filter are involved. Consider
for (i <- 1 to 3;
j <- 1 to 3 if (i + j) % 2 == 0;
k <- 1 to 3) yield i ^ j ^ k
versus
(1 to 3).flatMap { i =>
(1 to 3).filter(j => (i + j) % 2 == 0).flatMap { j =>
(1 to 3).map { k => i ^ j ^ k }
}
}