How to print a value outside a for loop in scala? - scala

I am new to scala and would like to know way to access val which is defined inside for loop and would like to write that val to a file outside for loop.
def time[A](logFile: String, description: String)(job: => A): Unit = {
var totalDuration: Long = 0
for (i <- 1 to 3) {
val currentTime = System.currentTimeMillis
val result = job
val finalTime = System.currentTimeMillis
val duration = finalTime - currentTime
totalDuration = if (totalDuration == 0) duration else totalDuration.min(duration)
}
val pw = new PrintWriter(new FileOutputStream(new File(logFile),true))
pw.write(description + " " + result + " " + totalDuration +" ms"+"\n")
pw.flush()
pw.close
}
In the above code i am calculating my result which contains the length of bytes read from other function and would like to calculate the time it takes to read the total bytes. I would like to iterate 3 times and take the minimum of all the three. The val result contains the bytes length which also needs to be written in a file. i get a error because i am accessing the result val outside the scope of for loop. Can someone please help me solve this error. How can i access the val result outside for loop to write it to a file ?
Thanks in advance!!

While your question is answered, the for loop is not in it's typical form, which would look more like this:
def time[A] (logFile: String, description: String) (job: => A): Unit = {
val (result, totalDuration): (A, Long) = (for { i <- 1 to 3
currentTime = System.currentTimeMillis
result = job
finalTime = System.currentTimeMillis
duration = finalTime - currentTime
} yield (result, duration)).minBy {case (r, d) => d}
val pw = new PrintWriter (new FileOutputStream (new File (logFile), true))
pw.write (description + " " + result + " " + totalDuration +" ms"+"\n")
pw.flush()
pw.close
}
If I understood your code correctly. I don't know whether a side effect yields to different results for each job invocation.
I missed the internal discussion of the for-loop invention/definition, why the keyword val should be omitted here, but it is quiet handy.
What is more important, is, that you usually have all temporary assignments in the for (...(here part)...) { not here}. The consequences of round or curly braces in the first part aren't totally clear to me, but if you use round parens, you have terminate most statements with a semicolon.
scala> for (i <- 1 to 3;
| j <- 4 to 5;
| k = j-i;
| l = k/2) yield l * l;
res2: scala.collection.immutable.IndexedSeq[Int] = Vector(1, 4, 1, 1, 0, 1)
Note that neither i, nor j, k, l where declared as val or var.
scala> for {i <- 1 to 3
| j <- 4 to 5
| k = j-i
| l = k/2} yield l * l;
res3: scala.collection.immutable.IndexedSeq[Int] = Vector(1, 4, 1, 1, 0, 1)
You will find multiple questions here, which explain, how a for-loop is and can be translatet to a flatMap/map-combination, eventually with filter:
scala> for {i <- 1 to 3
| j <- 4 to 5
| k = j-i
| if (k > 1)
| l = k/2 } yield l * l;
res5: scala.collection.immutable.IndexedSeq[Int] = Vector(1, 4, 1, 1, 1)
And instead of yielding just one value, you can yield a tuple, and assign by
val (a:X, b:Y) = (for ..... yield (aa, bb))
The
yield (result, duration)).minBy {case (r, d) => d}
takes a tuple (result, duration) and selects the minimum by duration, but yields both values.

you can use yield. Yield will return data from for loop after completion of loop and use that data accordingly. Since I do not have your code. see this example
val j = for (i <- 1 to 10) yield i
println(j)
output of j will be
Vector(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

For replacing your for loop to calculate the total duration of some jobs that are executed sequentially, you could use foldLeft

Make use of yield or you can use any of the fold method. Or if you are good with recursion you can use a tailrec method which returns what is Desired. Yield is the most simplest way to do it.
val answer = for(i<- 1 to 10) yield i
println(answer) // Vector(1,2,3,4,5,6,7,8,9,10)

Related

List whose elements depend on the previous ones

Suppose I have a list of increasing integers. If the difference of 2 consecutive numbers is less than a threshold, then we index them by the same number, starting from 0. Otherwise, we increase the index by 1.
For example: for the list (1,2,5,7,8,11,15,16,20) and the threshold = 3, the output will be: (0, 0, 1, 1, 1, 2, 3, 3, 4).
Here is my code:
val listToGroup = List(1,2,5,7,8,11,15,16,20)
val diff_list = listToGroup.sliding(2,1).map{case List(i, j) => j-i}.toList
val thres = 2
var j=0
val output_ = for(i <- diff_list.indices) yield {
if (diff_list(i) > thres ) {
j += 1
}
j
}
val output = List.concat(List(0), output_)
I'm new to Scala and I feel the list is not used efficiently. How can this code be improved?
You can avoid the mutable variable by using scanLeft to get a more idiomatic code:
val output = diff_list.scanLeft(0) { (count, i) =>
if (i > thres) count + 1
else count
}
Your code shows some constructs which are usually avoided in Scala, but common when coming from procedural langugues, like: for(i <- diff_list.indices) ... diff_list(i) can be replaced with for(i <- diff_list).
Other than that, I think your code is efficient - you need to traverse the list anyway and you do it in O(N). I would not worry about efficiency here, more about style and readability.
My rewrite to how I think it would be more natural in Scala for the whole code would be:
val listToGroup = List(1,2,5,7,8,11,15,16,20)
val thres = 2
val output = listToGroup.zip(listToGroup.drop(1)).scanLeft(0) { case (count, (i, j)) =>
if (j - i > thres) count + 1
else count
}
My adjustments to your code:
I use scanLeft to perform the result collection construction
I prefer x.zip(x.drop(1)) over x.sliding(2, 1) (constructing tuples seems a bit more efficient than constructing collections). You could also use x.zip(x.tail), but that does not handle empty x
I avoid the temporary result diff_list
val listToGroup = List(1, 2, 5, 7, 8, 11, 15, 16, 20)
val thres = 2
listToGroup
.sliding(2)
.scanLeft(0)((a, b) => { if (b.tail.head - b.head > thres) a + 1 else a })
.toList
.tail
You don't need to use mutable variable, you can achieve the same with scanLeft.

Getting specific incremental key values into an array

I have a list which I zipped with indices:
val fun_i_map_e = (list.indices zip list).toMap
Now, I want to get each key's value incremented by num:Int :
for (k<-0 until list.length by num)
for ((k,v) <- fun_i_map_e) {
bufferArray += v}
The idea here is something like this in Java:
for (k = 0; k <= list.length; k+= num){
//increment key k each time and store value into dynamic array }
However, I'm getting very random and complete trash output. I would appreciate if someone can help as I'm new in Scala.
You are almost there. All you need is to shape your for function with yield as given below
val bufferArray = for (k <- 0 until list.length by num) yield fun_i_map_e(k)
I hope the answer is helpful
val list = List[Int](5, 6, 7, 8)
val map = list.indices.zip(list).toMap
val num: Int = 15
val incremantedKeys = map.keys.map { k => k + num }
println("Original keys:")
println(map.keys)
println
println(s"Keys incremented by $num:")
println(incremantedKeys)

Scala functional code for iteration with a value forwarded to next iteration

How to make this code more functional, where a value from the current iteration is preserved into the next (variable last),
def f(i: Int): Int = ???
var last = -1
for (v <- xs) yield {
val start = f(v)
val end = f(start)
val res = if (last == start - 2) "abc" else "xyz"
last = end
res
}
I think foldLeft should work. You can pass the value that you will need in the next iteration and the result in a tuple
val list = (1 to 10 by 2)
//> list : scala.collection.immutable.Range = Range(1, 3, 5, 7, 9)
val last = -1
list.foldLeft((last, List[String]())) {
case (r, c) => println(s"Current - $c last - ${r._1}")
(c, r._2 :+ if (...) "abc" else "xyz")
// c will be the value that you need to pass to the next iteration
// r._2 will contain the list which you would have got with your for comprehension
}
//> Current - 1 last - -1
//| Current - 3 last - 1
//| Current - 5 last - 3
//| Current - 7 last - 5
//| Current - 9 last - 7
Noticed this approach with scanLeft (inspired in #mohit approach using foldLeft), here on a pre-processed collection of pairs for start and end, namely for instance
val a = Array((1,2), (3,4), (5,6))
Then in what follows, assume s stands for start and e for end, and so
a.scanLeft((-1,-1,-1)) { case(acc, (s,e)) => (s,e,acc._2) }.drop(1)
which produces triplets with start, end and last,
Array((1,2,-1), (3,4,2), (5,6,4))
over which we can apply the if-else expression; altogether,
a.scanLeft((-1,-1,-1)) { case(acc, (s,e)) => (s,e,acc._2) }.
drop(1).
map(t => if (t._3 == t._1 - 2) "abc" else "xyz")

How to capture inner matched value in indexWhere vector expression?

Using a Vector[Vector[Int]] reference v, and the expression to find a given number num:
val posX = v.indexWhere(_.indexOf(num) > -1)
Is there any way to capture the value of _.indexOf(num) to use after the expression (i.e. the posY value)? The following signals an error 'Illegal start of simple expression':
val posX = v.indexWhere((val posY = _.indexOf(num)) > -1)
If we do not mind using a variable then we can capture indexOf() value of inner Vector (_ in the below code) in a var and use it later to build the y position:
val posX = v.indexWhere(_.indexOf(num) > -1)
val posY = v(posX).indexOf(num)
There are lots of nice functional ways to do this. The following is probably one of the more concise:
val v = Vector(Vector(1, 2, 3), Vector(4, 5, 6), Vector(7, 8, 9))
val num = 4
val Some((posY, posX)) = v.map(_ indexOf num).zipWithIndex.find(_._1 > -1)
// posY: Int = 0
// posX: Int = 1
Note that there's a lot of extra work going on here, though—we're creating a couple of intermediate collections, parts of which we don't need, etc. If you're calling this thing a lot or on very large collections, you unfortunately may need to take a more imperative approach. In that case I'd suggest bundling up all the unpleasantness:
def locationOf(v: Vector[Vector[Int]])(num: Int): Option[(Int, Int)] = {
var i, j = 0
var found = false
while (i < v.size && !found) {
j = 0
while (j < v(i).size && !found)
if (v(i)(j) == num) found = true else j += 1
if (!found) i += 1
}
if (!found) None else Some(i, j)
}
Not as elegant, but this method is probably going to be a lot faster and more memory efficient. It's small enough that it isn't likely to contain any of the bugs that this kind of programming is so prone to, and it's referentially transparent—all the mutation is local.
From my armchair,
scala> val v = Vector(Vector(1, 2, 3), Vector(4, 5, 6), Vector(7, 8, 9))
scala> v.zipWithIndex collectFirst {
| case (e, i) if (e indexOf num) >= 0 =>
| (i, e indexOf num)
| }
res7: Option[(Int, Int)] = Some((1,0))
I haven't done the armchair math, but that's one intermediate collection compared to Travis's. But see Travis's comment that the result inner index is computed twice here, and the whole point was not to do that.
Here is a solution that will only evaluate up until it finds the required element. I personally find it more readable and you can reuse it across programs. You can obviously make this more general if need be.
val v = Vector(Vector(1, 2, 3), Vector(4, 5, 6))
def findElem(i: Int, vs: Vector[Vector[Int]]): (Int, Int) =
(for {
row <- vs.indices.toStream
col <- vs(row).indices.toStream
if vs(row)(col) == i
} yield (row, col)).head
findElem(5, v) // (1, 1)
You could remove the .toStream methods if you want all positions. Using the .toStream just means that you will only evaluate up until the first occurrence.

Strange results when using Scala collections

I have some tests with results that I can't quite explain.
The first test does a filter, map and reduce on a list containing 4 elements:
{
val counter = new AtomicInteger(0)
val l = List(1, 2, 3, 4)
val filtered = l.filter{ i =>
counter.incrementAndGet()
true
}
val mapped = filtered.map{ i =>
counter.incrementAndGet()
i*2
}
val reduced = mapped.reduce{ (a, b) =>
counter.incrementAndGet()
a+b
}
println("counted " + counter.get + " and result is " + reduced)
assert(20 == reduced)
assert(11 == counter.get)
}
The counter is incremented 11 times as I expected: once for each element during filtering, once for each element during mapping and three times to add up the 4 elements.
Using wildcards the result changes:
{
val counter = new AtomicInteger(0)
val l = List(1, 2, 3, 4)
val filtered = l.filter{
counter.incrementAndGet()
_ > 0
}
val mapped = filtered.map{
counter.incrementAndGet()
_*2
}
val reduced = mapped.reduce{ (a, b) =>
counter.incrementAndGet()
a+b
}
println("counted " + counter.get + " and result is " + reduced)
assert(20 == reduced)
assert(5 == counter.get)
}
I can't work out how to use wildcards in the reduce (code doesnt compile), but now, the counter is only incremented 5 times!!
So, question #1: Why do wildcards change the number of times the counter is called and how does that even work?
Then my second, related question. My understanding of views was that they would lazily execute the functions passed to the monadic methods, but the following code doesn't show that.
{
val counter = new AtomicInteger(0)
val l = Seq(1, 2, 3, 4).view
val filtered = l.filter{
counter.incrementAndGet()
_ > 0
}
println("after filter: " + counter.get)
val mapped = filtered.map{
counter.incrementAndGet()
_*2
}
println("after map: " + counter.get)
val reduced = mapped.reduce{ (a, b) =>
counter.incrementAndGet()
a+b
}
println("after reduce: " + counter.get)
println("counted " + counter.get + " and result is " + reduced)
assert(20 == reduced)
assert(5 == counter.get)
}
The output is:
after filter: 1
after map: 2
after reduce: 5
counted 5 and result is 20
Question #2: How come the functions are being executed immediately?
I'm using Scala 2.10
You're probably thinking that
filter {
println
_ > 0
}
means
filter{ i =>
println
i > 0
}
but Scala has other ideas. The reason is that
{ println; _ > 0 }
is a statement that first prints something, and then returns the > 0 function. So it interprets what you're doing as a funny way to specify the function, equivalent to:
val p = { println; (i: Int) => i > 0 }
filter(p)
which in turn is equivalent to
println
val temp = (i: Int) => i > 0 // Temporary name, forget we did this!
val p = temp
filter(p)
which as you can imagine doesn't quite work out the way you want--you only print (or in your case do the increment) once at the beginning. Both your problems stem from this.
Make sure if you're using underscores to mean "fill in the parameter" that you only have a single expression! If you're using multiple statements, it's best to stick to explicitly named parameters.