问题
In the book that I'm studying there is an exercise:
Write a loop that swaps adjacent elements of an array of integer. For example
Array(1,2,3,4,5)becomesArray(2,1,4,3,5). My solution is:
var v = Array(0,1,2,3,4,5,6,7,8,9)
for (i <- 0 until v.length by 2) {
var temp = 0
temp = v(i+1); v(i+1) = v(i); v(i) = temp
}
This algorithm works fine but isn't written fully exploiting the potential of Scala, it is written as if I wrote in C++. In fact, the following exercise asks:
Repeat the preceding assignment, but produce a new array with the swapped values. Use for/yield.
Now I tried with:
val a = ArrayBuffer(1,2,3,4,5)
var res = for (i <- 0 until a.length by 2) yield a(i)
for (i <- 1 until a.length by 2) res(i-1)=a(i) <---------eclipse give me an error
The error is: "value update is not a member of scala.collection.immutable.IndexedSeq[Int]"
How can I solve this task? I understand that the syntax "for / yield" is very powerful, but I don't know how to use it.
回答1:
There is a sliding function that does exactly what you need:
(for {
i <- Array(1,2,3,4,5).sliding(2,2)
j <- i.reverse
} yield j).toArray
回答2:
I am working through Scala for the Impatient myself to refresh my Scala coding skills. Given the concepts introduced by this point in the book, I believe the author is looking for the following:
val a = Array(1, 2, 3, 4, 5)
for (i <- 0 until a.length)
yield
if (i % 2 == 0)
if (i == a.length-1) a(i)
else a(i+1)
else a(i-1)
回答3:
In your generator, you use 0 until v.length by 2, which is an IndexedSeq. This being your input type, yield will produce the same collection type for res.
Since immutable.IndexedSeq is immutable, you cannot modify it. Hence res(i-1)=a(i), which would update the item at i-1, is not allowed.
So, one option would be to convert res to a mutable collection before you go on.
An often preferable option would be to solve it without updating. Here an example using foldLeft, which iterates over our IndexedSeq and builds up a new, flattened Array[Int]
val array = Array(1,2,3,4,5)
val result = (
for ( i <- 0 until array.length by 2)
yield
if (i < array.length-1)
Array(array(i+1), array(i))
else
Array(array(i))
).foldLeft (Array[Int]()) ((a,b) => a ++ b )
回答4:
The error is because res is an immutable sequence (a Vector), which cannot be updated in-place. Vector does have an updated(index: Int, elem: A) method, however, which returns a new Vector with the updated element.
I'm not sure what the writer of the exercise had in mind - using for/yield seems a little awkward here, but you could use grouped():
val a = Array(1,2,3,4,5) //> a : Array[Int] = Array(1, 2, 3, 4, 5)
val swapped = (for (i <- a.grouped(2)) yield i.reverse).flatten.toArray
//> swapped : Array[Int] = Array(2, 1, 4, 3, 5)
A neater way without for/yield, using flatMap is also possible
a.grouped(2).toArray.flatMap(_.reverse)
//> res5: Array[Int] = Array(2, 1, 4, 3, 5)
回答5:
Just a new approach:
(for (i<-0 to arr.length-2 by 2) yield Array(arr(i+1), arr(i))).flatten.toArray
回答6:
Here is my solution:
def swap(a: Array[Int]): Array[Int] = {
for (elem <- 0 until a.length)
yield {
if (elem % 2 == 0) {
if (elem == a.length - 1) a(elem)
else a(elem + 1)
}
else a(elem - 1)
}
}.toArray
回答7:
var result = for(j<- 0 until (a.length,2);
i<- 1 to 0 by -1;
if (j+i < a.length) )
yield a(j+i)
来源:https://stackoverflow.com/questions/22756814/scala-for-yield-syntax