I have a var permutedTables = HashMap[List[Int], List[String, String]] defined globally. I first populate the Hashmap with the keys in a method, which works.
print(permutedTables) :
Map(List(1,2,3,4) -> List(),
List(2,4,5,6) -> List(), etc...)
The problem occurs when I want to update the values (empty lists) of the HashMap inside a for loop (inside a second method). In other words, I want to add tuples (String, String) in the List() for each key.
for(pi_k <- permutedTables.keySet){
var mask = emptyMask;
mask = pi_k.foldLeft(mask)((s, i) => s.updated(i, '1'))
val maskB = Integer.parseInt(mask,2)
val permutedFP = (intFP & maskB).toBinaryString
// attempt 1 :
// permutedTables(pi_k) :+ (url, permutedFP)
// attempt 2 :
// permutedTables.update(pi_k, permutedTables(pi_k):::List((url, permutedFP)))
}
The values do not update. I still have empty lists as values. I don't understand what is wrong with my code.
EDIT 1: When I call print(permutedTables) after any of the two attempts (inside the loop), the value seem updated, but when I call it outside of the loop, the Lists are empty
EDIT 2: The second attempt in my code seems to work now(!). But why does first not work ?
The second attempt in my code seems to work now(!). But why does first not work ?
Because what you do in the first case is get a list from permutedTables, add an element and throw away the result without storing it back. It would work if you mutated the value, but a List is immutable. With List, you need
permutedTables += pi_k -> permutedTables(pi_k) :+ (url, permutedFP)
Or, as you saw, update.
You can use e.g. ArrayBuffer or ListBuffer as your value type instead (note that you need :+= instead of :+ to mutate them), and convert to your desired type at the end. This is going to be rather more efficient than appending to the end of the list, unless the lists are quite small!
Finally, note that you generally want either var or a mutable type, not both at the same time.
Related
pqr:String
xyz:List[(String,String),(String,String),......]
could be one pair or many so using map and I want to update so converting ListBuffer
var abc:ListBuffer[(String,String)] = xyz.to[ListBuffer]
abc.map(x => x._2 = pqr)
in above line I am getting an error reassignment to val
How can I update second string in every element of listBuffer ?
Scala places a big emphasis on immutable data. That is, generally in Scala you don't want to change existing values; you want to make new data that represents the changes you want. Your input is of type List, which is immutable. An immutable type will never become mutable; when you do to[ListBuffer], you're making a new list buffer which is unrelated to the previous, and the new list buffer is mutable.
If we have xyz a List[(String, String)], then we can use map to change the second element.
val myNewList = xyz.map { case (x, _) => (x, pqr) }
Note that xyz is not changed. That's the point. We made a new list with the changes intact. You can't change immutable data.
(Minor note: If you're using Scala 3, you can remove the word case from the above example, as tuple destructuring is inferred in Scala 3)
With a background from object-oriented programming I am not able to understand how to make immutable lists in Scala.
Example; I want to make a list of 10 random people:
object MyApplication extends App {
val numberOfPersons = 10 : Int
val listOfPersons = makeListOfPersons(numberOfPersons) : List[Person]
def makeListOfPersons( numberOfPersons : Int ) : List[Person] = {
// TODO: return a immutable list of 10 persons
}
}
class Person {
/**
Generic content,
like age and name.
* */
}
What is the "correct" way of making an immutable list in Scala?
If you know what collection type you want, you may be able to use the tabulate method on that type:
List.tabulate(10)(makePerson)
In this case makePerson is a function that takes an Int and returns the Person object for that Int.
If you don't care about the collection type, you can call map on the range 1 to 10 like this:
(1 to 10).map(makePerson)
If you don't need to use the Int parameter, you can do this:
List.tabulate(10)(_ => makeRandomPerson())
In this particular case,
List.fill(numberOfPersons){ codeThatCreatesASinglePerson }
seems most appropriate.
In most other cases: Nil creates an empty list, x :: y prepends an element x to list y.
If you want to append to list, instead of prepending to it, then you can take a collection.mutable.ListBuffer, append to it all the elements that you want to have in the list, and then call toList when you're done... or just use the built-in factory methods that do exactly that.
As the default List in Scala is immutable, the right way to add an element is to return a new list with the new element plus the older elements.
As a matter of fact, List has two methods, among others:
+:
++
The first one takes an element, add it as the first element and the rest of the list as it's tail and then returns the resulting list.
The other one takes another "collection" as parameter and adds it to the first list at the start.
List has another methods for adding the new element as the last one.
In Scala, these operations are permitted but take into consideration that always a new instance will be retrieved with the requested modifications as all objects are immutable by default.
As for your code goes, you could try with something like this:
object MyApplication extends App {
val numberOfPersons: Int = 10
val listOfPersons: List[Person] = makeListOfPersons(numberOfPersons)
def makeListOfPersons( numberOfPersons : Int ) : List[Person] = {
(1 to numberOfPersons).foldLeft(List.empty[Person]){ (accum, elem) =>
new Person() :: accum
}
}
}
(1 to numberOfPersons) creates a range, which could be seen as a List of ints, which will be traversed by foldLeft. This method will iterate through that list, and receives a seed, in this case an empty list of Person. Then, for every element in the int's list, a new Person is created and add to the list, returned as is the last expression and used the accumulator for the next iteration. Finally, a list of ten instances of Person is retrieved.
There are 5 ways to create List in scala:
Lisp style:
val list = 1::2::3::Nil
this style can also be thought of as a Haskell or functional programming (FP) style.
Java Style:
val list = List(1,2,3)
Scala List with range method
List.range(1, 10)
Create scala List with fill
List.fill(3)(5)
Scala List with tabulate
List.tabulate(5)(n => n * n)
element of the list are created according to the function we supply.
for more info please read this :
Preferred way to create a Scala list
How do you get and remove an arbitrary element from a mutable HashSet in Scala (similar to python set pop method)? Also what would be the performance of the api?
For extracting and removing elements in undefined order from a mutable hash set, try a combination of head and -= (remove):
import scala.collection.mutable.HashSet
def pop[A](hs: HashSet[A]): A = {
val a = hs.head
hs -= a
a
}
val example = HashSet.empty[Int] ++ (0 to 9)
while (!example.isEmpty) {
val p = pop(example)
println("Pop element: " + p)
}
I'm not sure whether it's caching any keys or hashes internally, but afaik it's either just O(1) or amortized O(1).
#Andrey's answer above should suffice to answer your question as he said
you can use .head function to pop an element.
Here are some more details.
Sets are one of the collection libraries of Scala which provide both mutable and immutable methods. If you want specific element to be removed from Sets then there is - and + methods. - method is used for removing an element from a Set and a new Set is returned. Similarly + method is used for adding an element in a Set which also returns a new Set with the element added. So you can write pop and set functions that will remove and add specific elements.
def popFromSet[T](set: Set[T], stringToPop: T) = {
set - stringToPop
}
def setToSet[T](set: Set[T], stringToPop: T) = {
set + stringToPop
}
And you can use them as
popFromSet(stringSet, "second")
setToSet(popFromSet(stringSet, "second"), "second2")
popFromSet(intSet, 2)
....
List way
You can do the above Set to List
If you have a HashSet as
Set("first", "second", "third")
You can get the second element popped out by doing
val hashList = hashSet.toList
hashList(hashList.indexOf("second"))
and if you want to remove the second element from the HashSet then
hashSet - hashList(hashList.indexOf("second"))
I hope the answer is helpful
I came across a weird functionality of Scala where the following two are not equivalent:
var map = Map[A,B]()
map += ( key -> (valueGen(key)))
does not give the same result as
var map = Map[A,B]()
val result = valueGen(key)
map += ( key -> result)
The second snippet does what you expect it to while the first one does not add correctly to the map, it instead overwrites the previous value so that the map only contains the most recently written value to it instead of all the values added into it.
I've seen this before, and it only causes problems when the valueGen function and this code is recursive together. I believe this is because expressions in parentheses are not guaranteed to be executed first. Parentheses only bind operators. Scala must be interpreting the += on the map like this:
map = map + (expression)
When it executes map + (expression), it reads the map operand to the plus operator first and holds it. Then it attempts to evaluate (expression). In the case (expression) contains the call to the valueGen function, it makes the call and then adds it to the cached map from this particular call. If the call to valueGen ends up recursing around and calling this function (and modifying the map first), this will overwrite those changes with the cached version from this call + the result. That is why you want to call the valueGen function separately from the += operator if your function is recursive.
When I run
object test {
def main(args: Array[String]) {
var map = Map[String,Int]()
map += ("hello" -> (valueGen("hello")))
map += ("bye" -> (valueGen("bye")))
println(map)
}
def valueGen(x: String) = x.length
}
I get
Map(hello -> 5, bye -> 3)
Could you provide a runnable example of what you are seeing?
I'm have a map that looks like this: Map[ A -> Collection[B]]. This map gets updated in a loop - the special thing is however, that updates mostly just mean adding an element B to the Collection[B] (for some key A).
I am trying to find out if I can get some speedup by changing the type of my Collection from List[ ] to ListBuffer[ ].
Up to now my code looked like this (simplified):
var incoming = new HashMap[A, List[B]() {
override def default(a: A) = List()
}
..
for(b < someCollectionOfBs){
..
incoming(b.getA) = b :: incoming(b.getA)
..
}
This works fine. Now, I changed the type of the map so it looks like this:
var incoming = new collection.mutable.HashMap[A, ListBuffer[B]() {
override def default(a: A) = collection.mutable.ListBuffer()
}
..
for(b < someCollectionOfBs){
..
incoming(b.getA) += b
..
}
Note the change in how the element B is added to the collection in the 2nd example (no more immutable List, hence we do not need to create and assign new collection...).
But. This does not work: incoming(X) += .. does not update the value of the map for X, actually it does not change anything.
What am I missing here? I thought that I should be able to update the values of a mutable HashMap... So, if my values are mutable collections, why can't I just add elements to those?
The default is returned when the key is not found, but it does not update the map with the default value. You can use getOrElseUpdate for that.
incoming.getOrElseUpdate(b.getA, ListBuffer()) += b
That should do what you want.
Additional note:
If you're concerned about performance, I don't think replacing List with ListBuffer will buy you much, because you are prepending to a List and that should be very fast. ListBuffer is handy when you want to append to a list. You should look at using java.util.HashMap and see if that helps.