I am at a beginner level in Scala, I am trying the following code:
var i: Int = 0
for (i <- 0 to 10) {
if (i == 2) {
i += 1
}
println(i)
}
When I increment i the compiler says Value += is not member of Int.
You're declaring i twice, one at the outer scope and one in the inner. Your for comprehension looks at the inner i, which is a val, not a var, thus shadowing the external declaration.
Bind to a different name:
var counter: Int = 0
for (i <- 0 to 10) {
if (i == 2) {
counter += 1
}
println(counter)
}
Note you can do this without declaring an outer variable at all, using count:
val count = (0 to 10).count(i => i == 2)
println(count)
Edit:
From your comments, I understand you want to print all numbers other than 2. For that you need to negate your condition:
if (i != 2) {
counter += 1
}
Or if you just want to filter out 2:
(0 to 10).filter(_ != 2).foreach(println)
Edit 2:
From you comments, it looks like a while loop is better for what you're trying to achieve:
var i = 0
while (i < fruits.length) {
if (fruits(i) == "Banana") {
i += 1
println(i + " " + fruits(i))
} else if (fruits(i) == "Orange") {
i += 1
println(i + " " + fruits(i))
}
}
But this code will run into an infinite loop since you're only incrementing i if the conditions are met. Other than that, since your doing i + 1, you might be going out of bounds if the last element equals "Banana" or "Orange", so you might want to rethink what you're doing. You'll probably run into an
As mentioned in Yuval's answer, you're declaring i twice. Not only that, but the inner one is implicitly immutable, therefore making it impossible for you to mutate it (that's why you get a compilation error).
To achieve the same effect you get from mutation you can use a guard in the for comprehension, like this:
for (i <- 0 to 10 if i != 2) {
println(i)
}
This code can be seamlessly translated (and that's what the compiler actually does) to the following
(0 to 10).withFilter(i => i != 2).foreach(i => println(i))
The new error mentioned in the comment looks like:
scala> :pa
// Entering paste mode (ctrl-D to finish)
var i: Int = 0
for(i <- 0 to 10)
{
if (i == 2)
{
i += 1
}
println(i)
}
// Exiting paste mode, now interpreting.
<pastie>:19: error: value += is not a member of Int
Expression does not convert to assignment because receiver is not assignable.
i += 1
^
It should say i instead of receiver for the simple case, where the LHS is not a complex expression, but you get the idea.
Also, nobody mentioned this:
scala> :pa
// Entering paste mode (ctrl-D to finish)
object X {
var i: Int = 0
for(i <- 0 to 10)
{
if (i == 2)
{
this.i += 1
}
println(this.i)
}}
// Exiting paste mode, now interpreting.
defined object X
scala> X
0
0
1
1
1
1
1
1
1
1
1
res3: X.type = X$#1129829c
Related
Recently, I've started learning Scala for school project. The assignment says that we have to delete elements of an unsorted array, without leaving "holes" in the array. I've made the following code:
private var _list = new Array[NAW](20)
private var _highestIndex = 0;
def removeAllbyName(name : String): Unit = {
for(i <- 0 until _highestIndex){
if(_list(i).name == name)
deleteByIndex(i)
}
}
def deleteByIndex(i : Int) : Unit = {
if(i != -1){
for(x <- i until _highestIndex){
_list(x) = _list(x + 1)
}
_highestIndex -= 1
}
}
I filled the array with 10 instances, the highestIndex will be 10 and after the first removal 9. But the for-loop still keeps counting to 9, which results in a null-pointer exception, even though we use "until". The debugger does recognise that _highestIndex is 9. Can somebody please explain why this is happening?
Thanks in advance!
0 until _highestIndex only gets evaluated once.
for (i <- 0 until _highestIndex) {
if (_list(i).name == name)
deleteByIndex(i)
}
Is equivalent to:
val range = 0 until _highestIndex
for (i <- range) {
if (_list(i).name == name)
deleteByIndex(i)
}
You can see that the range is determined only once.
You could try using a while loop instead, or a guard in your if statement.
Change your for-loop inside deleteByIndex like this to avoid exception
for(
x <- i until highestIndex
if (x + 1) < highestIndex
)
list(x) = list(x + 1)
I would like to simplify this:
var countA: Int = 0
var countB: Int = 0
if (validItem) {
if (region.equalsIgnoreCase( "US" )) {
if (itemList > 0) {
countB = 1
} else {
countA = 1
}
} else {
countB = 1
}
} else {
countA = 1
}
How do I use ternary operator in scala.
You should not need to use a ternary operator in Scala. In Scala, if is an expression not a statement, you can say val x = if (b) 1 else 2.
The usage of var in your example also points to a problem, because you can usually avoid this when you use the if as an expression.
Let's try to break down the code to avoid the var, i.e. first remove all if statements that are not expressions with a corresponding else and always provide both values:
var countA: Int = ???
var countB: Int = ???
if (validItem) {
if (region.equalsIgnoreCase("US")) {
if (itemList > 0) {
countA = 0
countB = 1
} else {
countA = 1
countB = 0
}
} else {
countA = 0
countB = 1
}
} else {
countA = 1
countB = 0
}
Now we can define the condition for which either of countA and countB is one:
val isUS = region.equalsIgnoreCase("US")
val hasItems = itemList > 0
val isA = !validItem || (isUS && !hasItems)
val isB = !isA
// or: val isB = validItem && (!isUS || hasItems)
and then:
val countA = if (isA) 1 else 0
val countB = if (isB) 1 else 0
I think the short answer is that in Scala there is no ?: ternary operator. Although you can imitate the syntax using implicits (see #jwvh's answer), I think it doesn't really simplify anything.
There are a couple of important properties of the conventional ?:
it always has two branches
following from the previous property, the ternary operator always returns a value (this is mostly the point of using ?:)
val result: Int = if (true) 1 else 2
// result is 1
branches are evaluated lazily
if (true) 1 else (0/0) // returns 1
if (false) 0/0 else 2 // returns 2
// i.e. 0/0 is not evaluated
As you see, in Scala if-else (with else) construction satisfies these properties. This is not the case for if-else construction in some other languages, like C or Java, because it doesn't return a value.
So the bottom line is that in Scala you don't need a ternary operator, because you can just use if-else.
UPDATE
As Alexey Romanov mentions in the comments, if statement without else actually satisfies the first condition as well. When you write
val result = if (true) 1
it actually means if (true) 1 else (), so result will have type AnyVal instead of Int, because the return type of the if expression is the lowest common bound of the both branches (Int and Unit in this case).
This might be a bit confusing for a "newbie", but you could attach a ternary method to the Boolean class like so.
implicit class Ternary[T](condition: Boolean) {
def ??(a: => T, b: => T): T = if (condition) a else b
}
Usage:
(4 == 4)??("yes","no") // res0: String = yes
("abc".length < 2).??(1,0) // res1: Int = 0
List('c').isEmpty.??('X','+') // res2: Char = +
To expand on #0__'s answer (if that is his/her real name), you can also use tuples to assign to two variables at once.
val (countA, countB) =
if (validItem) {
if (region.equalsIgnoreCase("US")) {
if (itemList > 0) (0,1) else (1,0)
} else {
(0,1)
}
} else {
(1,0)
}
This is an old question and I'm taking a break from a current problem, so I thought I'd leave a basic pattern match solution.
val (countA, countB) =
(validItem, region.equalsIgnoreCase("US"), itemList > 0) match {
case (true, true, false) | (false, _, _) => (1, 0)
case _ => (0, 1)
}
I'm trying to assign a different value for each actor to the variable "file" in example class using its object in class A.
class A{
var a1=new Array[example](2)
def starting()= {
for(i <- 0 to 3){
if(i==0){
a1(i).file="L1.txt";
}
else if(i==1){
a1(i).file="L2.txt";
}
a1(i).start
}
}
}
class example extends Actor {
var file="default.txt"
var Handle = new A
def act()= {
loop{
var count=0
react{
//remaining code
}
}
}
This is throwing a nullpointerexception corresponding to the lines :
for(i <- 0 to 3){
if(i==0){
a1(i).file="L1.txt";
}
i'm a beginner in scala.. i somehow am unable to figure out the reason for this exception. Please help.
var a1=new Array[example](2) creates new Array with 2 nulls, so a1(i) is null.
Use var a1 = IndexedSeq.fill(2){ new example }
Off topic:
There is Code Review for such things, but your code is not scala way. Try to rewrite it.
For example:
scala> import actors.Actor._
import actors.Actor._
scala> val as = for ( fileName <- Seq("L1.txt", "L2.txt") )
| yield actor {
| var count = 0
| loop {
| receive {
| case t =>
| count += 1
| println(fileName + " " + count + " " + t)
| }
| }
| }
as: Seq[scala.actors.Actor] = List(scala.actors.Actor$$anon$1#ef82188, scala.actors.Actor$$anon$1#44616f65)
scala> as.foreach{ _ ! 's }
L2.txt 1 's
L1.txt 1 's
Apart from what #senia already diagnosed, you are allocating an array of 2 elements, then trying to iterate through 4 elements of it:
for(i <- 0 to 3){
which is surely going to produce an ArrayIndexOutOfBoundsException once i becomes 2. Loop condition should be for(i <- 0 to 1) or for(i <- 0 until 2) for this to work. Although there are indeed better, more Scala-ish ways to implement this.
probably the file "L1.txt" is not being located!
read this URL Read entire file in Scala?
Some algorithms execute a while loop with condition true and will (for sure) end at some point with a return statement inside the body of the while loop. E.g.:
def foo: Int = {
while(true) {
// At some time, the while loop will do a return statement inside its body
if( ... )
return 0
}
}
Simple example (without semantic sense):
def foo: Int = {
var i = 0
while(true) {
i += 1
if(i == 10)
return 0
}
}
The Scala compiler complains about a type mismatch, because the while loop has type Unit and the compiler does not know, that the while loop will at some point return a value. We could fix this with a workaround like:
def foo: Int = {
var i = 0
while(true) {
i += 1
if(i == 10)
return 0
}
0 // !
}
But this looks ugly. Is there a better workaround ? Or even a better solution for this kind of problem ?
You could throw an exception:
def foo: Int = {
var i = 0
while(true) {
i += 1
if(i == 10)
return 0
}
throw new IllegalStateException("This should never happen")
}
The compiler will stop complaining about the type mismatch, and since the while loop always returns something, the exception will never be thrown. And if it is, you will quickly find out where you did something wrong :).
There are other ways to write this loop which are more idomatic and Scala-esque, but given the code you provided, this will get the job done in a clear and simple way.
Maybe you should just use tail recursion instead. It should end up compiling down to very similar bytecode:
import scala.annotation.tailrec
def foo: Int = {
#tailrec def bar(i: Int): Int = {
val j = i + 1
if (j == 10) return 0
else bar(j)
}
bar(0)
}
You might even want to make use of the default parameter value support:
#tailrec def foo(i: Int = 0): Int = {
val j = i + 1
if (j == 10) return 0
else foo(j)
}
Note that this way requires you to call the function as foo() not foo since it has an argument.
A more idiomatic way would be to use recursion. Something like this:
def foo: Int = {
import scala.annotation.tailrec
#tailrec def whileUnderTen(i: Int):Int = if ( i < 10) whileUnderTen(i+1) else 0
whileUnderTen(0)
}
For just these occasions, I have a "forever" construct defined in my personal standard library.
forever{
}
is in all ways equivalent to
while(true){
}
except that forever has type Nothing while the equivalent while construct has type Unit. Just one of those small extension capabilities that makes Scala such a joy.
How can I initialize a val that is to be used in another scope? In the example below, I am forced to make myOptimizedList as a var, since it is initialized in the if (iteration == 5){} scope and used in the if (iteration > 5){} scope.
val myList:A = List(...)
var myOptimizedList:A = null
for (iteration <- 1 to 100) {
if (iteration < 5) {
process(myList)
} else if (iteration == 5)
myOptimizedList = optimize(myList)
}
if (iteration > 5) {
process(myOptimizedList)
}
}
This may have been asked before, but I wonder if there is an elegant solution that uses Option[A].
Seems that you have taken this code example out of the context, so this solution can be not very suitable for your real context, but you can use foldLeft in order to simplify it:
val myOptimizedList = (1 to 100).foldLeft (myList) {
case (list, 5) => optimize(list)
case (list, _) => process(list); list
}
You can almost always rewrite some sort of looping construct as a (tail) recursive function:
#annotation.tailrec def processLists(xs: List[A], start: Int, stop: Int) {
val next = start + 1
if (start < 5) { process(xs); processLists(xs, next, stop)
else if (start == 5) { processLists( optimize(xs), next, stop) }
else if (start <= stop) { process(xs); processLists( xs, next, stop ) }
}
processLists(myList, 100, 1)
Here, you pass forward that data which you would otherwise have mutated. If you need to mutate a huge number of things it becomes unwieldy, but for one or two it is often as clear or clearer than doing the mutation.
It's often the case that you can rework your code to avoid the problem. Consider the simple, and common, example here:
var x = 0
if(something)
x = 5
else
x = 6
println(x)
This would be a pretty common pattern in most languages, but Scala has a better way of doing it. Specifically, if-statements can return values, so the better way is:
val x =
if(something)
5
else
6
println(x)
So we can make x a val after all.
Now, clearly your code can be rewritten to use all vals:
val myList:A = List(...)
for (iteration <- 1 to 5)
process(myList)
val myOptimizedList = optimize(myList)
for (iteration <- 5 to 100)
process(myOptimizedList)
But I suspect this is simply an example, not your real case. But if you're unsure how you might rearrange your real code to accomplish something similar, please show us what it looks like.
There's another technique (perhaps trick in this case) to delay initialization of
myOptimizedList which is to use a lazy val. Your example is very specific but the principal is still obvious, delay assignment of a val until it is first referenced.
val myList = List(A(), A(), A())
lazy val myOptimizedList = optimize(myList)
for (iteration <- 1 to 100) {
if (iteration < 5)
process(myList)
else if (iteration > 5)
process(myOptimizedList)
}
Note that the case iteration == 5 is ignored.