when I work on some task using scala , I wrote some code as follows:
object He {
def main(args: Array[String]): Unit = {
var myMatrix = Array.ofDim[String](3,3)
// build a matrix
for (i <- 0 to 1) {
for ( j <- 0 to 1) {
myMatrix(i)(j) = "faf";
}
}
var eventbuffer = for(i <- myMatrix) yield for(j <- i) yield j
var eventArray = for(i <- eventbuffer) yield i.toArray
var eventpool:Array[(String, Array[String])] = eventArray.toArray.map(son => (son(0), son))
}
}
I want to ask the question ,what's the differece between the eventbuffer and eventArray?Last,what will the eventpool be like? I am really confused,Thank for
helping me for that
In Scala an Array is just a JVM Array, while the various Buffers are actual classes.
An Array[String] ist the same as a String[] in Java.
You can think of an ArrayBuffer as an ArrayList in Java (they're very similar, but not equivalent) and of the ListBuffer as a Java LinkedList (again, similar, but not the same).
One should note however, that in your example eventbuffer is not a Buffer, but an Array of Arrays. In fact it is pretty much an exact copy of myMatrix, so the call to the toArray method is actually redundant.
Related
I'm having trouble with a nested for loop and using yield properly.
The problem is if I have two lists of the form List[(Int,Int)]
val ls = (1,5)::(3,2)::(5,3)::Nil
val ls_two = (1,9)::(5,9)::(6,7)::Nil
and now I want to create a third list only combining the key and both second int of all the lists so the result would be
val result = (1,5,9)::(5,3,9)::Nil
I've tried a few variations of something like this which none seem to work
val result = for(i <- ls) {
for(j <- ls_two) {
if(i._1 == j._1) yield (i._1,i._2,j._2)
}
}
I've tried placing the yield at the end of the for loop, it seems to work if i replace yield with println but i'm not sure how to do it with yield.
Also if you have a more functional approach to how to solve this it would be greatly appreciated, thanks!
The recommended approach here is not to "nest" the "loops" at all - but to create a single for-comprehension which uses a "guard":
val result = for {
i <- ls
j <- ls_two if i._1 == j._1
} yield (i._1,i._2,j._2)
I have the following bit of code in scala which is not working:
var tacTable : List[List[TACList]] = List(List())
def gen(p: Program) = {
for (i <- 0 to p.classes.length){
for (j <- 0 to p.classes(i).methods.length){
var tacInstr = new TACList()
tacTable(i)(j) = tacInstr //error: application does not take parameters
}
}
}
Apparently, it has to do with the fact that I'm using j to access the list and j is used in for...how can I solve this?
For convenience you can work with this other example which gives the same error:
var l : List[List[Int]] = List(List(1,2),List(3,4))
for (i <- 0 to l.length) {
for (j <- 0 to l.length) {
l(i)(j) = 8
}
}
Lists are immutable.
Try this instead:
val tacTable = p.classes.map { _.methods.map { _ =>
new TACList()
}
since I cannot comment on the initial post a sidenote here:
in a scala for-comprehension you can use multiple generators in a single for. so the nesting that you used is not necessary since you can use this:
for (i <- 0 to l.length; j <- 0 to l.length) {
// your code
}
furthermore, this does not seem to apply in your case but if you had a flat mapped result you should use the yield of the for comprehension instead of a mutation in the body
How do you iterate over two arrays of the same size, accessing the same index each iteration The Scala Way™?
for ((aListItem, bListItem) <- (aList, bList)) {
// do something with items
}
The Java way applied to Scala:
for(i <- 0 until aList.length ) {
aList(i)
bList(i)
}
Assume both lists are the same size.
tl;dr: There are trade-offs between speed and convenience; you need to know your use case to pick appropriately.
If you know both arrays are the same length and you don't need to worry how fast it is, the easiest and most canonical is to use zip inside a for-comprehension:
for ((a,b) <- aList zip bList) { ??? }
The zip method creates a new single array, however. To avoid that overhead you can use zipped on a tuple which will present the elements in pairs to methods like foreach and map:
(aList, bList).zipped.foreach{ (a,b) => ??? }
Faster still is to index into the arrays, especially if the arrays contain primitives like Int, since the generic code above has to box them. There is a handy method indices that you can use:
for (i <- aList.indices) { ??? }
Finally, if you need to go as fast as you possibly can, you can fall back to manual while loops or recursion, like so:
// While loop
var i = 0
while (i < aList.length) {
???
i += 1
}
// Recursion
def loop(i: Int) {
if (i < aList.length) {
???
loop(i+1)
}
}
loop(0)
If you are computing some value, rather than having it be a side effect, it's sometimes faster with recursion if you pass it along:
// Recursion with explicit result
def loop(i: Int, acc: Int = 0): Int =
if (i < aList.length) {
val nextAcc = ???
loop(i+1, nextAcc)
}
else acc
Since you can drop a method definition in anywhere, you can use recursion without restriction. You can add an #annotation.tailrec annotation to make sure it can be compiled down to a fast loop with jumps instead of actual recursion that eats stack space.
Taking all these different approaches to calculate a dot product on length 1024 vectors, we can compare these to a reference implementation in Java:
public class DotProd {
public static int dot(int[] a, int[] b) {
int s = 0;
for (int i = 0; i < a.length; i++) s += a[i]*b[i];
return s;
}
}
plus an equivalent version where we take the dot product of the lengths of strings (so we can assess objects vs. primitives)
normalized time
-----------------
primitive object method
--------- ------ ---------------------------------
100% 100% Java indexed for loop (reference)
100% 100% Scala while loop
100% 100% Scala recursion (either way)
185% 135% Scala for comprehension on indices
2100% 130% Scala zipped
3700% 800% Scala zip
This is particularly bad, of course, with primitives! (You get similarly huge jumps in time taken if you try to use ArrayLists of Integer instead of Array of int in Java.) Note in particular that zipped is quite a reasonable choice if you have objects stored.
Do beware of premature optimization, though! There are advantages to in clarity and safety to functional forms like zip. If you always write while loops because you think "every little bit helps", you're probably making a mistake because it takes more time to write and debug, and you could be using that time optimizing some more important part of your program.
But, assuming your arrays are the same length is dangerous. Are you sure? How much effort will you make to be sure? Maybe you shouldn't make that assumption?
If you don't need it to be fast, just correct, then you have to choose what to do if the two arrays are not the same length.
If you want to do something with all the elements up to the length of the shorter, then zip is still what you use:
// The second is just shorthand for the first
(aList zip bList).foreach{ case (a,b) => ??? }
for ((a,b) <- (aList zip bList)) { ??? }
// This avoids an intermediate array
(aList, bList).zipped.foreach{ (a,b) => ??? }
If you instead want to pad the shorter one with a default value, you would
aList.zipAll(bList, aDefault, bDefault).foreach{ case (a,b) => ??? }
for ((a,b) <- aList.zipAll(bList, aDefault, bDefault)) { ??? }
In any of these cases, you can use yield with for or map instead of foreach to generate a collection.
If you need the index for a calculation or it really is an array and you really need it to be fast, you will have to do the calculation manually. Padding missing elements is awkward (I leave that as an exercise to the reader), but the basic form would be:
for (i <- 0 until math.min(aList.length, bList.length)) { ??? }
where you then use i to index into aList and bList.
If you really need maximum speed you would again use (tail) recursion or while loops:
val n = math.min(aList.length, bList.length)
var i = 0
while (i < n) {
???
i += 1
}
def loop(i: Int) {
if (i < aList.length && i < bList.length) {
???
loop(i+1)
}
}
loop(0)
Something like:
for ((aListItem, bListItem) <- (aList zip bList)) {
// do something with items
}
Or with map like:
(aList zip bList).map{ case (alistItem, blistItem) => // do something }
Updated:
For iterating without creating an intermediates, you can try:
for (i <- 0 until xs.length) ... //xs(i) & ys(i) to access element
or simply
for (i <- xs.indices) ...
I would do something like this:
aList.indices foreach { i =>
val (aListItem, bListItem) = (aList(i), bList(i))
// do something with items
}
for {
i <- 0 until Math.min(list1.size, list2.size)
} yield list1(i) + list2(i)
Or something like that which checks bounds etc.
I am new to Scala and try to use it in a functional way. Here are my questions:
Why can't I create a new binding for 'cnt' variable with function return value using '<-' operator?
How can increment immutable variable in a functional way (similar to Haskell <-) ? For the sake of experiment I don't want to use mutable vars.
import scala.io.Source
object MyProgram {
def main(args: Array[String]): Unit = {
if (args.length > 0) {
val lines = Source.fromFile(args(0)).getLines()
val cnt = 0
for (line <- lines) {
cnt <- readLines(line, cnt)
}
Console.err.println("cnt = "+cnt)
}
}
def readLines(line: String, cnt:Int):Int = {
println(line.length + " " + line)
val newCnt = cnt + 1
return (newCnt)
}
}
As for side effects, I could never expect that (line <- lines) is so devastating! It completely unwinds lines iterator. So running the following snippet will make size = 0 :
val lines = Source.fromFile(args(0)).getLines()
var cnt = 0
for (line <- lines) {
cnt = readLines(line, cnt)
}
val size = lines.size
Is it a normal Scala practice to have well-hidden side-effects like this?
You could fold on lines like so:
val lines = Source.fromFile(args(0)).getLines()
val cnt = lines.foldLeft(0) { case (count, line) => readLines(line, count) }
Console.err.println("cnt = "+cnt)
Your readLines method does side-effect with the call to println, but using foldLeft guarantees left-to-right processing of the list, so the output should be the same.
Why can't I reassign immutable 'cnt' variable with function return value using '<-' operator?
Why would you? If you has java experience, <- has the simular meaning as : in for(Item x: someCollection). It is just a syntactic sugar for taking current item from collection and naming it, it is not a bind operator in general.
Moreover, isn't reassign immutable oxymoron?
How can increment immutable variable in a functional way (similar to Haskell <-)?
Scala people usually use .zipWithIndex but this will work only if you're going to use counter inside for comprehension:
for((x, i) <- lines.zipWithIndex) { println("the counter value is" + i) }
So I think you need to stick with lines.count or use fold/reduce or = to assign new value to variable.
<- is not an operator, just a syntax used in for expressions. You have to use =. If you want to use <- it must be within the for-iteration-expression. And you cannot increment a val. If you want to modify that variable, make it a var.
Much like this question:
Functional code for looping with early exit
Say the code is
def findFirst[T](objects: List[T]):T = {
for (obj <- objects) {
if (expensiveFunc(obj) != null) return /*???*/ Some(obj)
}
None
}
How to yield a single element from a for loop like this in scala?
I do not want to use find, as proposed in the original question, i am curious about if and how it could be implemented using the for loop.
* UPDATE *
First, thanks for all the comments, but i guess i was not clear in the question. I am shooting for something like this:
val seven = for {
x <- 1 to 10
if x == 7
} return x
And that does not compile. The two errors are:
- return outside method definition
- method main has return statement; needs result type
I know find() would be better in this case, i am just learning and exploring the language. And in a more complex case with several iterators, i think finding with for can actually be usefull.
Thanks commenters, i'll start a bounty to make up for the bad posing of the question :)
If you want to use a for loop, which uses a nicer syntax than chained invocations of .find, .filter, etc., there is a neat trick. Instead of iterating over strict collections like list, iterate over lazy ones like iterators or streams. If you're starting with a strict collection, make it lazy with, e.g. .toIterator.
Let's see an example.
First let's define a "noisy" int, that will show us when it is invoked
def noisyInt(i : Int) = () => { println("Getting %d!".format(i)); i }
Now let's fill a list with some of these:
val l = List(1, 2, 3, 4).map(noisyInt)
We want to look for the first element which is even.
val r1 = for(e <- l; val v = e() ; if v % 2 == 0) yield v
The above line results in:
Getting 1!
Getting 2!
Getting 3!
Getting 4!
r1: List[Int] = List(2, 4)
...meaning that all elements were accessed. That makes sense, given that the resulting list contains all even numbers. Let's iterate over an iterator this time:
val r2 = (for(e <- l.toIterator; val v = e() ; if v % 2 == 0) yield v)
This results in:
Getting 1!
Getting 2!
r2: Iterator[Int] = non-empty iterator
Notice that the loop was executed only up to the point were it could figure out whether the result was an empty or non-empty iterator.
To get the first result, you can now simply call r2.next.
If you want a result of an Option type, use:
if(r2.hasNext) Some(r2.next) else None
Edit Your second example in this encoding is just:
val seven = (for {
x <- (1 to 10).toIterator
if x == 7
} yield x).next
...of course, you should be sure that there is always at least a solution if you're going to use .next. Alternatively, use headOption, defined for all Traversables, to get an Option[Int].
You can turn your list into a stream, so that any filters that the for-loop contains are only evaluated on-demand. However, yielding from the stream will always return a stream, and what you want is I suppose an option, so, as a final step you can check whether the resulting stream has at least one element, and return its head as a option. The headOption function does exactly that.
def findFirst[T](objects: List[T], expensiveFunc: T => Boolean): Option[T] =
(for (obj <- objects.toStream if expensiveFunc(obj)) yield obj).headOption
Why not do exactly what you sketched above, that is, return from the loop early? If you are interested in what Scala actually does under the hood, run your code with -print. Scala desugares the loop into a foreach and then uses an exception to leave the foreach prematurely.
So what you are trying to do is to break out a loop after your condition is satisfied. Answer here might be what you are looking for. How do I break out of a loop in Scala?.
Overall, for comprehension in Scala is translated into map, flatmap and filter operations. So it will not be possible to break out of these functions unless you throw an exception.
If you are wondering, this is how find is implemented in LineerSeqOptimized.scala; which List inherits
override /*IterableLike*/
def find(p: A => Boolean): Option[A] = {
var these = this
while (!these.isEmpty) {
if (p(these.head)) return Some(these.head)
these = these.tail
}
None
}
This is a horrible hack. But it would get you the result you wished for.
Idiomatically you'd use a Stream or View and just compute the parts you need.
def findFirst[T](objects: List[T]): T = {
def expensiveFunc(o : T) = // unclear what should be returned here
case class MissusedException(val data: T) extends Exception
try {
(for (obj <- objects) {
if (expensiveFunc(obj) != null) throw new MissusedException(obj)
})
objects.head // T must be returned from loop, dummy
} catch {
case MissusedException(obj) => obj
}
}
Why not something like
object Main {
def main(args: Array[String]): Unit = {
val seven = (for (
x <- 1 to 10
if x == 7
) yield x).headOption
}
}
Variable seven will be an Option holding Some(value) if value satisfies condition
I hope to help you.
I think ... no 'return' impl.
object TakeWhileLoop extends App {
println("first non-null: " + func(Seq(null, null, "x", "y", "z")))
def func[T](seq: Seq[T]): T = if (seq.isEmpty) null.asInstanceOf[T] else
seq(seq.takeWhile(_ == null).size)
}
object OptionLoop extends App {
println("first non-null: " + func(Seq(null, null, "x", "y", "z")))
def func[T](seq: Seq[T], index: Int = 0): T = if (seq.isEmpty) null.asInstanceOf[T] else
Option(seq(index)) getOrElse func(seq, index + 1)
}
object WhileLoop extends App {
println("first non-null: " + func(Seq(null, null, "x", "y", "z")))
def func[T](seq: Seq[T]): T = if (seq.isEmpty) null.asInstanceOf[T] else {
var i = 0
def obj = seq(i)
while (obj == null)
i += 1
obj
}
}
objects iterator filter { obj => (expensiveFunc(obj) != null } next
The trick is to get some lazy evaluated view on the colelction, either an iterator or a Stream, or objects.view. The filter will only execute as far as needed.