I am currently learning scala. I am reading Scala for the impatient.
1.)
Guards
Is there a difference?
for (i <- 0 to 10)if (i % 2 == 0) println(i)
for (i <- 0 to 10 if i % 2 == 0) println(i)
2.)
I always see the following symbol => but they never explain what it does.
Sometimes I think it is a cast but then it is something completely different, I hope you can clear things up.
1.) Yes, there is a difference, the first if a normal if statement inside of the closure you pass to the for-comprehension. The second is an actual guard. It will actually call withFilter on the range, before calling foreach. So the translation of the two things will look like this:
0.to(10).foreach(i => if(i % 2 == 0) println(i) )
0.to(10).withFilter(x => x % 2 == 0).foreach(i => println(i))
To add a little more context, calling withFilter or even just filter instead of using a normal if statement has some benefits. In a for comprehension, you can have nested calls to map, flatmap, filter, collect etc. so if you add guards, you can prevent a lot af calls from actually happening. For example:
for {
x <- 0 until 10
y <- 10 until 20
} {
if(x % 2 == 0) println(x*y)
}
would call the actual closure 100 times
for {
x <- 0 until 10
if x % 2 == 0
y <- 10 until 20
} println(x*y)
this will only call it 50 times, while the result stays the same.
2.)
=> separates the argument list of a function/closure from the body.
This case e: NumberFormatException => None is a part of a partial function. Here the => separates the "argument" e from the body None.
In a type signature like in someFunction(i: (A) => Int) it implies that i is of the type Function1[A,Int], read "function from A to Int".
Related
I'm new to scala and I'm trying to figure out how tuple works. I'm trying to call the xth element of a tuplle where x is a variable but it seems not to work, how should I do?
for (x <- 1 to 2; j <- 0 to (N-1)) yield((j, index._x), (x-1,index._x))
In particular the index._x seem to not work
It is possible to do this using the Product trait, though, as mentioned in the comment, this is not really a good idea or the intended way tuples are supposed to be used:
val indexed = index.productIterator.toIndexedSeq
for {
x <- 1 to 2
j <- 0 until N
} yield ((j, indexed(x-1)), (x-1, indexed(x-1))
or better yet (get rid of indexed access, it's yuky):
index.productIterator.take(2).toSeq.zipWithIndex
.flatMap { case (value, index) =>
(0 until N).map { j => ((j, value), (index, value)) }
}
I'll say it again though: there is about 99% chance there is a better way to do what you are actually trying to do. Tuples are meant for grouping data, not iterating over it (use collections for that).
I am using a for comprehension on a stream and I would like to know how many iterations took to get o the final results.
In code:
var count = 0
for {
xs <- xs_generator
x <- xs
count = count + 1 //doesn't work!!
if (x prop)
yield x
}
Is there a way to achieve this?
Edit: If you don't want to return only the first item, but the entire stream of solutions, take a look at the second part.
Edit-2: Shorter version with zipWithIndex appended.
It's not entirely clear what you are attempting to do. To me it seems as if you are trying to find something in a stream of lists, and additionaly save the number of checked elements.
If this is what you want, consider doing something like this:
/** Returns `x` that satisfies predicate `prop`
* as well the the total number of tested `x`s
*/
def findTheX(): (Int, Int) = {
val xs_generator = Stream.from(1).map(a => (1 to a).toList).take(1000)
var count = 0
def prop(x: Int): Boolean = x % 317 == 0
for (xs <- xs_generator; x <- xs) {
count += 1
if (prop(x)) {
return (x, count)
}
}
throw new Exception("No solution exists")
}
println(findTheX())
// prints:
// (317,50403)
Several important points:
Scala's for-comprehension have nothing to do with Python's "yield". Just in case you thought they did: re-read the documentation on for-comprehensions.
There is no built-in syntax for breaking out of for-comprehensions. It's better to wrap it into a function, and then call return. There is also breakable though, but it works with Exceptions.
The function returns the found item and the total count of checked items, therefore the return type is (Int, Int).
The error in the end after the for-comprehension is to ensure that the return type is Nothing <: (Int, Int) instead of Unit, which is not a subtype of (Int, Int).
Think twice when you want to use Stream for such purposes in this way: after generating the first few elements, the Stream holds them in memory. This might lead to "GC-overhead limit exceeded"-errors if the Stream isn't used properly.
Just to emphasize it again: the yield in Scala for-comprehensions is unrelated to Python's yield. Scala has no built-in support for coroutines and generators. You don't need them as often as you might think, but it requires some readjustment.
EDIT
I've re-read your question again. In case that you want an entire stream of solutions together with a counter of how many different xs have been checked, you might use something like that instead:
val xs_generator = Stream.from(1).map(a => (1 to a).toList)
var count = 0
def prop(x: Int): Boolean = x % 317 == 0
val xsWithCounter = for {
xs <- xs_generator;
x <- xs
_ = { count = count + 1 }
if (prop(x))
} yield (x, count)
println(xsWithCounter.take(10).toList)
// prints:
// List(
// (317,50403), (317,50721), (317,51040), (317,51360), (317,51681),
// (317,52003), (317,52326), (317,52650), (317,52975), (317,53301)
// )
Note the _ = { ... } part. There is a limited number of things that can occur in a for-comprehension:
generators (the x <- things)
filters/guards (if-s)
value definitions
Here, we sort-of abuse the value-definition syntax to update the counter. We use the block { counter += 1 } as the right hand side of the assignment. It returns Unit. Since we don't need the result of the block, we use _ as the left hand side of the assignment. In this way, this block is executed once for every x.
EDIT-2
If mutating the counter is not your main goal, you can of course use the zipWithIndex directly:
val xsWithCounter =
xs_generator.flatten.zipWithIndex.filter{x => prop(x._1)}
It gives almost the same result as the previous version, but the indices are shifted by -1 (it's the indices, not the number of tried x-s).
I'm trying to print out all the factors of every number in a list.
Here is my code:
def main(args: Array[String])
{
val list_of_numbers = List(1,4,6)
def get_factors(list_of_numbers:List[Int]) : Int =
{
return list_of_numbers.foreach{(1 to _).filter {divisor => _ % divisor == 0}}
}
println(get_factors(list_of_numbers));
}
I want the end result to contain a single list that will hold all the numbers which are factors of any of the numbers in the list. So the final result should be (1,2,3,4,6). Right now, I get the following error:
error: missing parameter type for expanded function ((x$1) => 1.to(x$1))
return list_of_numbers.foreach{(1 to _).filter {divisor => _ % divisor == 0}}
How can I fix this?
You can only use _ shorthand once in a function (except for some special cases), and even then not always.
Try spelling it out instead:
list_of_numbers.foreach { n =>
(1 to n).filter { divisor => n % divisor == 0 }
}
This will compile.
There are other problems with your code though.
foreach returns a Unit, but you are requiring an Int for example.
Perhaps, you wanted a .map rather than .foreach, but that would still be a List, not an Int.
A few things are wrong here.
First, foreach takes a function A => Unit as an argument, meaning that it's really just for causing side effects.
Second your use of _, you can use _ when the function uses each argument once.
Lastly your expected output seems to be getting rid of duplicates (1 is a factor for all 3 inputs, but it only appears once).
list_of_numbers flatMap { i => (1 to i) filter {i % _ == 0 }} distinct
will do what you are looking for.
flatMap takes a function from A => List[B] and produces a simple List[B] as output, list.distinct gets rid of the duplicates.
Actually, there are several problems with your code.
First, foreach is a method which yields Unit (like void in Java). You want to yield something so you should use a for comprehension.
Second, in your divisor-test function, you've specified both the unnamed parameter ("_") and the named parameter (divisor).
The third problem is that you expect the result to be Int (in the code) but List[Int] in your description.
The following code will do what you want (although it will repeat factors, so you might want to pass it through distinct before using the result):
def main(args: Array[String]) {
val list_of_numbers = List(1, 4, 6)
def get_factors(list_of_numbers: List[Int]) = for (n <- list_of_numbers; r = 1 to n; f <- r.filter(n%_ == 0)) yield f
println(get_factors(list_of_numbers))
}
Note that you need two generators ("<-") in the for comprehension in order that you end up with simply a List. If you instead implemented the filter part in the yield expression, you would get a List[List[Int]].
I've created this simple anonymous function
var b = (x : Int) => if(x % 2 == 0) x + 1 else x
and it works great. After that I tried to add another statement after the if and before the x+1 statement.
var b = (x : Int) => if(x % 2 == 0) println(x) x + 1 else x
and a that point I received the following compiler error
Cannot resolve symbol x
Please can anyone let me know why this happen?
The reason this happens is that although Scala does not require the use of semi-colons most of the time (unlike Java), since the compiler is more equipped to infer where statements/expressions end, if you have 2 statements/expressions on 1 line then you need to separate them for the compiler.
Your first anonymous function works since if(x % 2 == 0) x + 1 else x is 1 expression.
The compiler is complaining with the second one though since if(x % 2 == 0) println(x) is considered 1 statement. Hence, the next statement starts and there is now no context for x.
Other posters have given you a solution to break the right-side of the function down into separate statements so I won't duplicate - just adding an explanation of why the compilation error occurs since you said you are learning the language. Google about the use of semi-colons in Scala to find out more.
Use this. You need the braces to indicate these are multiple lines:
var b = (x : Int) => if(x % 2 == 0) {
println(x)
x + 1
} else x
Or you can do this.. you need to put that semi colon to indicate to compiler they are separate statements:
var b = (x : Int) => if(x % 2 == 0) { println(x); x + 1 } else x
val total_breaks = //a random number
total_breaks match {
case i if(i < 0) => chartTemplate.setAttribute("totalBreaks", 0)
case _ => chartTemplate.setAttribute("totalBreaks", total_breaks)
}
I was thinking there was a function in Scala that could shorten this. I thought min did this but I guess not. I can't seem to find documentation on min, max, etc.
Something like total_breaks.min(0). Display 0 if under 0 if not display total_breaks.
Also is there a way do something like this
(4 + 5) match {
case 0 => println("test")
case _ => println(_) //i need to display the number passed into match? Is this not possible?
}
If I do case i => println(i) is that the same as case _ => ? Is that the fallback?
There are methods min and max defined in GenTraversableOnce, and thus available on sequences. You can use them as:
scala> List(1, -4, 0).min
resN: -4
There is also min and max defined in RichInt, that work like operators on anything that can be converted to RichInt, typically your vanilla integers:
scala> -4 min 0
resN: -4
So if you want something that returns your number, say x if x is greater than 0 and 0 otherwise, you can write:
scala> x max 0
That means you can rewrite your pattern-matching as:
chartTemplate.setAttribute("totalBreaks", total_breaks max 0)
For your second question, _ and i are both valid patterns that will match anything. The difference is that in the first case you do not bind what you have matched to a variable. Using println(_) is wrong, though; as such, it corresponds to an anonymous function that prints its first argument. So if you don't want to repeat the expression (4 + 5), you should indeed write your pattern and code as:
case i => println(i)