Creating empty scala mutable sequence and adding to it - scala

I am trying to have to create an mutable sequence and then add to that sequence.
import scala.collection.mutable.Seq
// my case class
case class Apple(id: Int, color: String)
var sequence : Seq[Apple] = Seq.empty
for(a<-1 to 4) {
sequence :+ Apple(a, "green")
println("$$$$")
}
print(sequence)
However it's just empty.
result
$$$$
$$$$
$$$$
ArrayBuffer()defined class Apple
import scala.collection.mutable.Seq
sequence: scala.collection.mutable.Seq[Apple] = ArrayBuffer()
I tried to use ListBuffer but its just empty
var y = new scala.collection.mutable.ListBuffer[ Apple]
for(a<-1 to 4) {
y :+ Apple(a, "green")
println("$$$$")
}
y.size
Am I using the wrong structure to add my Apple to? I eventually want to create a DF from my list of Apples
Update
When I was using ListBuffer I forgot to add the () to var y = new scala.collection.mutable.ListBuffer[ Apple] and it should have rather been
var y = new scala.collection.mutable.ListBuffer[ Apple]()
And like specified in the comments the operator should have been +=

Mutable collections that you can append elements to on the right are of type Growable, and appending is done with addOne. Not every Seq is Growable -- an ArraySeq for example is is a mutable Seq backed by a fixed size array, and while you can change its elements, you can't append to it. You could use for example an ArrayBuffer instead
import scala.collection.mutable.ArrayBuffer
case class Apple(id: Int, color: String)
val sequence: ArrayBuffer[Apple] = ArrayBuffer.empty
for(a<-1 to 4) {
sequence.addOne(Apple(a, "green"))
println("$$$$")
}
print(sequence)
if you want to iteratively build a collection, consider using a Builder instead.

There is a better, functional way to do this:
List.tabulate(4)(a => Apple(a+1,"green"))
tabulate creates a List of a given size and allows you to initialise elements of the list based on their index.

Related

working with RDDS and collections in Scala

I have the below function that takes an array of means of type Likes (type Likes=Int)
and an RDD of numbers of type Likes (likesVector). For each number in the likesVector RDD, it computes the distance from each mean in means array and chooses the mean which has the least distance (val distance = (mean-number).abs). While I expect a result of type Map[Likes,Array[Likes]], I get an empty map. Map[Likes,Array[Likes]] represents (mean->Array of number-nearest numbers).
What is the best way to achieve this? I suspect it has a lot to do with the mutability of Scala collections.
def assignDataPoints(means:Array[Likes],likesVector:RDD[Likes]): Map[Likes,Array[Likes]] ={
var likes_Mean = IntMap(1->1)
var likes_mean_final = mutable.Map.empty[Likes,Array[Likes]]
likesVector.map(dataPoint => {
means.foldLeft(Array.empty[Likes])( (accumulator, mean)=> {
val dist= computeDistance(dataPoint,mean)
val nearestMean = if (dist < accumulator(0)) {
accumulator(0)=dist
accumulator(0)
} else{
accumulator(0)
}
val b= IntMap(nearestMean.toInt -> dataPoint)
println("b:"+ b)
likes_mean_final ++ likes_Mean.intersectionWith(b,(_, av, bv: Likes) => Array(av, bv))
accumulator
})})
likes_mean_final.toMap
}
The reason for your empty map is that you are using ++ operation here in the line:
likes_mean_final ++ likes_Mean.intersectionWith(b,(_, av, bv: Likes) => Array(av, bv))
++ operation returns a new map hence we are creating a new object and not changes the current value
The operation for mutating the current mutable map is ++=. So you should use:
likes_mean_final ++= likes_Mean.intersectionWith(b,(_, av, bv: Likes) => Array(av, bv))
Also no need to use var in your context as you are not reassigning values to the same references.
But you should not use mutability in Scala.

Adding key-value pairs to Map in scala

I am very new to scala, and want to create a hash map with the key being a candidate, and value being number of votes. Something like this: {(1:20),(2:4),(3:42),..}.
I`ve attempted with the following code:
val voteTypeList = textFile.map(x=>x(2)) //String array containing votes: [3,4,2,3,2,1,1,1,9,..]
var voteCount:Map[String,Int] = Map()
voteTypeList.foreach{x=>{
if (voteCount.contains(x)){ //Increment value
var i: Integer = voteCount(x)
voteCount.updated(x, i+1)
// print(voteCount(x))
}
else{ //Create new key-value pair
// println(x)
voteCount += (x -> 1)
}}}
print(voteCount.size)
But the voteCount does not get created and .size returns 0.
Thank you!
The problem you're encountering is caused by using a var to hold an immutable Map. Change that to a val holding a mutable Map and it works.
val voteCount:collection.mutable.Map[String,Int] = collection.mutable.Map()
Having said that, there are a number of other issues with the code that makes it non-idiomatic to the Scala way of doing things.
What you really want is something closer to this.
val voteCount = voteTypeList.groupBy(identity).mapValues(_.length)
Jwvh's answer is idiomatic but non-obvious and, if the list has very large numbers of duplicates, memory-heavy.
You might also consider the literal-minded (yet still Scalarific) way of doing this:
val voteCount = voteTypeList.foldLeft(Map(): Map[Int, Int]) { (v, x) =>
v + (x -> (v.getOrElse(x, 0) + 1))
}

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).

scala append to a mutable LinkedList

Please check this
import scala.collection.mutable.LinkedList
var l = new LinkedList[String]
l append LinkedList("abc", "asd")
println(l)
// prints
// LinkedList()
but
import scala.collection.mutable.LinkedList
var l = new LinkedList[String]
l = LinkedList("x")
l append LinkedList("abc", "asd")
println(l)
// prints
// LinkedList(x, abc, asd)
Why does the second code snippet works but the first one doesnt? This is on Scala 2.10
The documentation says If this is empty then it does nothing and returns that. Otherwise, appends that to this.. That is exactly, what you observed. If you really need a mutable list, I would suggest you to use scala.collection.mutable.ListBuffer instead, with it you can do
val lb = new ListBuffer[Int]
scala> lb += 1
res14: lb.type = ListBuffer(1)
scala> lb
res15: scala.collection.mutable.ListBuffer[Int] = ListBuffer(1)
scala> lb ++= Seq(1,2,3)
res17: lb.type = ListBuffer(1, 1, 2, 3, 1, 2, 3)
scala> lb
res18: scala.collection.mutable.ListBuffer[Int] = ListBuffer(1, 1, 2, 3, 1, 2, 3)
As I understand it is related to First/Last (Nil) element in the list (if list is empty Nil is first and last element at the same time).
LinkedList (still) follows "primitive charm" strategy. So it does not try to add/append new data to/after Nil, to have possible result like this: {Nil, newElement}. (After all Nil should be last element)
Of course it could check if list is empty then put addingList to the beginning and Nil to the end. But this would be "too smart", I guess.
But, anyway append() returns "expecting" result Like this:
val addingList = new LinkedList[String]("a", "b")
val result = emptyList append addingList
result = {"a", "b"}. In this case it returns 'addingList' itself, and/but does not change initial list.
If we try to assign newElement to the next ref:
emptyList.next = LinkedList("whatever")
As result we would have emtyList changed like this:
LinkedList(null, whatever)
I.e. it creates fist element as null, since we have used next() assigning new/next element to it. So it moves Nil to the end, because first element which is null, has next reference to new element we added (addingElelement).
Because
"the "emptyList" is also the "head" link"
and head in our case head is Nil, but Nill can not have next, so it has to create new first element (which is has null value) with next() referece to our new addingElelement.
Personally I find it "too much primitive" and not "so much elegant". But it depends, I guess.
Task oriented story:
For my initial task (why I start thinking about this 'strange' list behaviour [even though it's mutable]) -- I wanted to use mutable list for a class/object called Dictionary which would keep Words in it (dictionary by default has not any words). And I would have methods like addWord(wod:String) for adding new words. For now my implementation will be changed (I'm not going to use this LinkedList, but rather MutableList. It seems it is more mutable than previous one):
object Dictionary {
val words = new mutable.MutableList[Word]();
def addWord(word: Word): Unit = {
words += word;
}
}
But possible implementation could be like this:
object Dictionary {
var words = new mutable.LinkedList[Word]();
def addWord(word: Word): Unit = {
if (words.isEmpty) {
words = words append( mutable.LinkedList[Word](word) ) // rely on append result
} else {
words append( mutable.LinkedList[Word](word) )
}
}
}
But then I have to use var instead of val, and I should transform every new Word to LinkedList, and my logic became more complicated.

Can't append to scala's mutable LinkedList?

I'm looking at the API and the :+ method returns a new LinkedList. The append method will only allow the appending of another linked list. The += method needs a var to work. Why would anyone ever need these if the LinkedList is mutable? What craziness is this?
If I had something like this in Java
final LinkedList myList = new LinkedList<String>();
mylist.add("balh");
How do I achieve the same thing in Scala?
If append can only take a LinkedList then why not use
mylist append LinkedList("something")
or
mylist append LinkedList(otherContainer: _*)
There is a reason for allowing only other LinkedLists in append, I think, because this guarantees the following:
l1 = LinkedList(1, 2, 3)
l2 = LinkedList(4)
l3 = LinkedList(5)
l1 append l2
// l1 == LinkedList(1, 2, 3, 4)
// l2 == LinkedList(4)
l2 append l3
// l1 == LinkedList(1, 2, 3, 4, 5)
// l2 == LinkedList(4, 5)
// l3 == LinkedList(5)
You can use a Buffer to build your values and convert it in the data structure using mapResult.
//Create a buffer which will build a linked list
val buf = new ArrayBuffer[String] mapResult { xs => LinkedList( xs:_* ) }
//You can append elements with +=, it is overriden to allow its use on a val
buf += "Something"
buf += "else"
//At the end you get your list
val lst = buf.result
// lst == LinkedList(Something, else)
Mutability is on the actual elements within the list and not on the structure that the list has (persistence). This is also stated in the scaladoc.
If returning a new List each time is not what you are after, and you cannot use var, you could always use the Java LinkedList.
val mylist = new java.util.LinkedList[String]
mylist add "something"
I'd stick with the Scala lists, if at all possible.
First, please pay more attention to the docs:
This class implements single linked lists where both the head (elem)
and the tail (next) are mutable.
So what it is giving you is mutable head and tail. These operations are represented through three methods:
append and insert change tail, so they receive a LinkedList as argument
update change the head of an element.
If you want a class that can grow, look at the classes extending Growable.