Using "next" in an "iterator" and getting type mismatch error - scala

I am writing my code in Scala and need to have a loop over a vector of points in an image but getting type mismatch error!. I can understand why I have the error but I don't know how to solve it. here is my code:
val output= new Mat (image.rows, image.cols,CV_8UC3,new Scalar(0, 0, 0))
val it = Iterator(vect1)
var vect3=new Array[Byte](3)
vect3(0)=0
vect3(1)=255.toByte
vect3(2)=0
var e= new Point(0,0)
while(it.hasNext){
e = it.next();
output.put(e.x.toInt,e.y.toInt,vect3)
}
and I am getting this error:
...
type mismatch;
found : scala.collection.mutable.ArrayBuffer[org.opencv.core.Point]
required: org.opencv.core.Point[
e = it.next()

By doing val it = Iterator(vect1), you are creating an iterator that iterates on vect1 itself, and not on vect1's elements. Thankfully, you don't need to create an iterator for that, because it already exists :
val vect1 = ArrayBuffer(1, 2, 3)
// vect1: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer(1, 2, 3)
val it = vect1.iterator
// it: Iterator[Int] = non-empty iterator
while (it.hasNext) {
println(it.next)
}
// 1
// 2
// 3
// res0: Unit = ()
Note that, according to the Scala API documentation, ArrayBuffer inherits from IterableLike. IterableLike basically means that a collection is iterable, so it makes sense that it defines a method which returns an iterator.
By the way, you can also avoid directly accessing the iterator entirely, using either the foreach method or a for comprehension, because IterableLike also defines the foreachmethod:
// foreach
vect1.foreach(p => output.put(p.x.toInt, p.y.toInt, vect3))
// for comprehension
for (p <- vect1) {
output.put(p.x.toInt, p.y.toInt, vect3)
}
Using the foreach method or the for comprehension is strictly equivalent: the compiler translates for comprehensions to one or more method calls; in this case, a call to foreach.

Related

appending elements to list of list in scala

i have created a empty scala mutable list
import scala.collection.mutable.ListBuffer
val list_of_list : List[List[String]] = List.empty
i want to append elements to it as below
filtered_df.collect.map(
r => {
val val_list = List(r(0).toString,r(4).toString,r(5).toString)
list_of_list += val_list
}
)
error that i am getting is
Error:(113, 26) value += is not a member of List[List[String]]
Expression does not convert to assignment because receiver is not assignable.
list_of_list += val_list
Can someone help
Your declaration seems wrong:
val list_of_list : List[List[String]] = List.empty
means that you've declared scala.collection.immutable.List whose operations return a new list without changing the current.
To fix the error you need to change the outer List type to ListBuffer that you imported above the declaration as follows:
val list_of_list : ListBuffer[List[String]] = ListBuffer.empty
Also it looks like you don't to use map here unless you want to modify your data collected from DataFrame, so you can change it to foreach:
filtered_df.collect.foreach {
r => {
val val_list = List(r(0).toString,r(4).toString,r(5).toString)
list_of_list += val_list
}
}
Furthermore you can make it in a functional way without resorting to ListBuffer, by using immutable List and foldRight as follows:
val list_of_list: List[List[String]] =
filtered_df.collect.toList
.foldRight(List.empty[List[String]])((r, acc) => List(r(0).toString,r(4).toString,r(5).toString) :: acc)
toList is used to achieve a stack safety when calling foldRight, because it's not stack safe for Arrays
More info about foldLeft and foldRight
You have to change that val list_of_list to var list_of_list. That alone would not be enough as you also have to change the type of list_of_list into a mutable alternative.

Found Unit, required Int

I have the following Scala code:
object Solution {
def getBestSolution(sumList: List[Int]): Int = {
return 0
}
def main(args: Array[String]) {
val t = readInt()
(0 until t).foreach({
val n = readInt()
val a = readLine().split(" ").map(_.toInt).toList
val sumList = a.scanLeft(0)(_ + _).tail.toList
//println(classOf[sumList])
println(sumList)
println(getBestSolution(sumList))
})
}
}
For it, I am getting this error:
file.scala:16: error: type mismatch;
found : Unit
required: Int => ?
println(getBestSolution(sumList))
^
one error found
Any idea what is causing this?
The argument you are passing to foreach is the result of executing the code block (which is a Unit), not a function.
Remove the outer parentheses (they do not really hurt anything, but are unnecessary and look ugly), and add _ => in the beginning:
(0 to t).foreach { _ =>
...
println(getBestSolution(sumList))
}
This is the proper syntax for creating an unnamed function. The stuff before => is the parameter list that the function accepts. In your case, you can just put an underscore there, because you do not need the value of the parameter. Or you could give it a name if you needed to do something with it, e.g.: (0 to t).foreach { x => println(x*x) }
you could have done it with simple for comprehension too instead of foreach
for(x <- 0 to t){
val n = readInt()
val a = readLine().split(" ").map(_.toInt).toList
val sumList = a.scanLeft(0)(_ + _).tail.toList
//println(classOf[sumList])
println(sumList)
println(getBestSolution(sumList))
}
To sum up, Programming in Scala book has pointed that Scala provides the for comprehension, which provides syntactically pleasing nesting of map, flatMap, and filter ... The for comprehension is not a looping construct, but is a syntactic construct the compiler reduces to map, flatMap, and filter.

How do I append to a listbuffer which is a value of a mutable map in Scala?

val mymap= collection.mutable.Map.empty[String,Seq[String]]
mymap("key") = collection.mutable.ListBuffer("a","b")
mymap.get("key") += "c"
The last line to append to the list buffer is giving error. How the append can be done ?
When you run the code in the scala console:
→$scala
scala> val mymap= collection.mutable.Map.empty[String,Seq[String]]
mymap: scala.collection.mutable.Map[String,Seq[String]] = Map()
scala> mymap("key") = collection.mutable.ListBuffer("a","b")
scala> mymap.get("key")
res1: Option[Seq[String]] = Some(ListBuffer(a, b))
You'll see that mymap.get("key") is an optional type. You can't add a string to the optional type.
Additionally, since you typed mymap to Seq[String], Seq[String] does not have a += operator taking in a String.
The following works:
val mymap= collection.mutable.Map.empty[String,collection.mutable.ListBuffer[String]]
mymap("key") = collection.mutable.ListBuffer("a","b")
mymap.get("key").map(_ += "c")
Using the .map function will take advantage of the optional type and prevent noSuchElementException as Łukasz noted.
To deal with your problems one at a time:
Map.get returns an Option[T] and Option does not provide a += or + method.
Even if you use Map.apply (mymap("key")) the return type of apply will be V (in this case Seq) regardless of what the actual concrete type is (Vector, List, Set, etc.). Seq does not provide a += method, and its + method expects another Seq.
Given that, to get what you want you need to declare the type of the Map to be a mutable type:
import collection.mutable.ListBuffer
val mymap= collection.mutable.Map.empty[String,ListBuffer[String]]
mymap("key") = ListBuffer("a","b")
mymap("key") += "c"
will work as you expect it to.
If you really want to have immutable value, then something like this should also work:
val mymap= collection.mutable.Map.empty[String,Seq[String]]
mymap("key") = Vector("a","b")
val oldValue = mymap.get("key").getOrElse(Vector[String]())
mymap("key") = oldValue :+ "c"
I used Vector here, because adding elements to the end of List is unefficient by design.

Appending element to list in Scala

val indices: List[Int] = List()
val featValues: List[Double] = List()
for (f <- feat) {
val q = f.split(':')
if (q.length == 2) {
println(q.mkString("\n")) // works fine, displays info
indices :+ (q(0).toInt)
featValues :+ (q(1).toDouble)
}
}
println(indices.mkString("\n") + indices.length) // prints nothing and 0?
indices and featValues are not being filled. I'm at a loss here.
You cannot append anything to an immutable data structure such as List stored in a val (immutable named slot).
What your code is doing is creating a new list every time with one element appended, and then throwing it away (by not doing anything with it) — the :+ method on lists does not modify the list in place (even when it's a mutable list such as ArrayBuffer) but always returns a new list.
In order to achieve what you want, the quickest way (as opposed to the right way) is either to use a var (typically preferred):
var xs = List.empty[Int]
xs :+= 123 // same as `xs = xs :+ 123`
or a val containing a mutable collection:
import scala.collection.mutable.ArrayBuffer
val buf = ArrayBuffer.empty[Int]
buf += 123
However, if you really want to make your code idiomatic, you should instead just use a functional approach:
val indiciesAndFeatVals = feat.map { f =>
val Array(q0, q1) = f.split(':') // pattern matching in action
(q0.toInt, q1.toDouble)
}
which will give you a sequence of pairs, which you can then unzip to 2 separate collections:
val (indicies, featVals) = indiciesAndFeatVals.unzip
This approach will avoid the use of any mutable data structures as well as vars (i.e. mutable slots).

Update a mutable map with default value in Scala

Consider the following code that counts the frequency of each string in the list and stores the results in the mutable map. This works great, but I don't understand where the += method is defined?! Is this some weird implicit conversion thing or what? I saw this code somewhere but it didn't include an explanation for the +=.
val list = List("a", "b", "a")
val counts = new scala.collection.mutable.HashMap[String, Int]().withDefaultValue(0)
list.foreach(counts(_) += 1)
counts
//> res7: scala.collection.mutable.Map[String,Int] = Map(a -> 2, b -> 1)
The apply of map returns an Int, but Int doesn't have a += and this method updates the map with a new value, so it looks as if the apply returns a mutable integer that has a += method...
This is not an implicit conversion - it is a desugaring.
Writing:
x += 1
desugars to:
x = x + 1
if the class of x does not have a += method defined on it.
In the same way:
counts("a") += 1
desugars to:
counts("a") = counts("a") + 1
because counts("a") is an Int, and Int does not have a += method defined.
On the other hand, writing:
x(expression1) = expression2
desugars to a call to the update method in Scala:
x.update(expression1, expression2)
Every mutable Map has an update method defined - it allows setting keys in the map.
So the entire expression is desugared to:
list.foreach(x => counts.update(x, counts(x) + 1))
This += is not to be confused with the += method on mutable.Maps in Scala. That method updates the entry in the map if that key already existed, or adds a new key-value pair. It returns the this reference, that is, the same map, so you can chain += calls. See ScalaDoc or the source code.
For these moments where you wonder what compiler magic is happening in a part of your code, scalac -print is your best friend (see this question).
If you do a scalac -print C.scala where C.scala is
package test
class C {
def myMethod() {
val counts = new scala.collection.mutable.HashMap[String, Int]().withDefaultValue(0)
counts("a") += 1
}
}
you get
package test {
class C extends Object {
def myMethod(): Unit = {
val counts: collection.mutable.Map = new collection.mutable.HashMap().withDefaultValue(scala.Int.box(0));
counts.update("a", scala.Int.box(scala.Int.unbox(counts.apply("a")).+(1)))
};
def <init>(): test.C = {
C.super.<init>();
()
}
}
It came as a surprise for me also, but apparently scalac will transform
map(key) =<op> rhs
to
map.update(key, map.apply(key) <op> rhs)