Select first 'N' elements from map in Scala - scala

Is there an elegant method of extracting first 'N' elements from a Map ?
I could create a new Map and iterate over the values that are to be selected, is there a function that accomplishes this ?

From the docs for the take method on Map:
Selects first n elements.
Note: might return different results for different runs, unless the
underlying collection type is ordered.
In the case of maps the collection isn't ordered, so don't count on getting the first n elements—in fact the concept of the first n elements doesn't even exist for maps.
But take will give you some first n elements, and it sounds like this is what you want:
scala> Map('a -> 1, 'b -> 2, 'c -> 3).take(2)
res1: scala.collection.immutable.Map[Symbol,Int] = Map('a -> 1, 'b -> 2)
In this case you happen to get the two elements that came first in the definition, but don't count on this happening.

Sounds like you're looking for a SortedMap, along with take(n) as discussed by others.

scala> val map = Map[String,Int]("one"->1,"two"->2,"three"->3)
map: scala.collection.immutable.Map[String,Int] =
Map(one -> 1, two -> 2, three -> 3)
scala> val n = 2
n: Int = 2
scala> val firstN = map.take(n)
firstN: scala.collection.immutable.Map[String,Int] = Map(one -> 1, two -> 2)

Related

How to add all the values of a map without using recurrsion or var

I want to add all the values in a map without using var or any mutable structures. I have tried to do something like this but it doens't work:
val mymap = ("a" -> 1, "b" -> 2)
val sum_of_alcohol_consumption =
for ((k,v) <- mymap ) yield (sum_of_alcohol_consumption += v)
I have been told that I can use .sum on a list
Please help
Thanks
You can use the .values function of a Map to return an Iterable List of its values (all of the Integers) and then call the .sum function on that:
val myMap = Map("a" -> 1, "b" -> 2)
val sum = myMap.values.sum
println(sum) // Outputs: 3
An equivalent answer to the more elegant use of sum is to use a fold operation. sum is implemented in a manner similar to this:
val myMap = Map("a" -> 1, "b" -> 2)
val sumAlcoholConsumption = myMap.values.foldLeft(0)(_ + _)
values returns a sequence of only the values in the map. The first foldLeft argument is the zero value (think of it as the initial value for an accumulator value) for the operation. The second argument is a function that adds the current value of the accumulator to the current element, returning the sum of the two values - and it is applied to each value in turn. That said, sum is a lot more convenient.
To get the only values of map, it provides a function values which will return iterable,we can directly appy sum function to it.
scala> val mymap = Map("a" -> 1, "b" -> 2)
mymap: scala.collection.immutable.Map[String,Int] = Map(a -> 1, b -> 2)
scala> mymap.values.sum
res7: Int = 3

scala map += operator with five pairs

I am having an issue with appending pairs to an existing Map. Once I reach the fifth pair of the Map, the Map reorders itself. The order is correct with 4 pairs, but as soon as the 5th is added it shifts itself. See example below (assuming I built the 4 pair Map one pair at a time.):
scala> val a = Map("a1" -> 1, "a2" -> 1, "a3" -> 1, "a4" -> 1)
a: scala.collection.immutable.Map[String,Int] = Map(a1 -> 1, a2 -> 1, a3 -> 1, a4 -> 1)
scala> a += ("a5" -> 1)
scala> a
res26: scala.collection.immutable.Map[String,Int] = Map(a5 -> 1, a4 -> 1, a3 -> 1, a1 -> 1, a2 -> 1)
The added fifth element jumped to the front of the Map and shifts the others around. Is there a way to keep the elements in order (1, 2, 3, 4, 5) ?
Thanks
By default Scala's immutable.Map uses HashMap.
From http://docs.oracle.com/javase/6/docs/api/java/util/HashMap.html:
This class makes no guarantees as to the order of the map; in particular, it does not guarantee that the order will remain constant over time
So a map is really not a table that contains "a1" -> 1, but a table that contains hash("a1") -> 1. The map reorders its keys based on the hash of the key rather than the key you put in it.
As was recommended in the comments, use LinkedHashMap or ListMap:
Scala Map implementation keeping entries in insertion order?
PS: You might be interested in reading this article: http://howtodoinjava.com/2012/10/09/how-hashmap-works-in-java/

Compare two Maps in Scala

Is there any pre-defined function that I can use to compare two Maps based on the key and give me the difference? Right now, I iterate Map1 and foreach key, I check if there is an element in Map2 and I pattern match to find the difference. Is there a much elegant way to do this?
Consider the difference between the maps converted into sets of tuples,
(m1.toSet diff m2.toSet).toMap
Try:
val diff = (m1.keySet -- m2.keySet) ++ (m2.keySet -- m1.keySet)
diff contains the elements that are in m1 and not in m2 and that are in m2 and not in m1.
This solution looks like right way:
scala> val x = Map(1 -> "a", 2 -> "b", 3 -> "c")
x: scala.collection.immutable.Map[Int,String] = Map(1 -> a, 2 -> b, 3 -> c)
scala> val y = Map(1 -> "a", 2 -> "b", 4 -> "d")
y: scala.collection.immutable.Map[Int,String] = Map(1 -> a, 2 -> b, 4 -> d)
scala> val diff : Map[Int, String] = x -- y.keySet
diff: Map[Int,String] = Map(3 -> c)
Found it here https://gist.github.com/frgomes/69068062e7849dfe9d5a53bd3543fb81
I think the -- operator will do what you're looking for: http://www.scala-lang.org/api/current/index.html#scala.collection.Map#--(xs:scala.collection.GenTraversableOnce[A]):Repr
Although this will probably only work given the assumption that Map2 is always a subset of Map1...

toMap when keys are repeated with different values

I have a list
val data = List(2, 4, 3, 2, 1, 1, 1,7)
with which I want to create a map such that values in above list are keys to new one with indeces as new values I tried
scala> data.zipWithIndex.toMap
res5: scala.collection.immutable.Map[Int,Int] = Map(1 -> 6, 2 -> 3, 7 -> 7, 3 -> 2, 4 -> 1)
but strangely it gives res5(1) as 6 but I want it to be 4.
I could solve it by
data.zipWithIndex groupBy (_._1) mapValues (w=>w.map(tuple=>tuple._2) min)
but is there any way I can pass a function f to toMap so that it creates map in desired way.
toMap is going to add each pair to the map in the order of the zipped list, and when you add a mapping k -> v to a map that already contains a k, the old value is simply replaced.
An easy fix is just to reverse the list after zipping the indices and before converting to a map:
data.zipWithIndex.reverse.toMap
Now the mappings 1 -> 6 and 1 -> 5 will be added before 1 -> 4, which means 1 -> 4 is the one you'll see in the result.

Different Representations of Scala HashMap

I've been playing around with the Scala HashMap and I've noticed two different representations of the HashMap. I was wondering if somebody could explain the difference of:
Map(123 -> 1)
and
{123=1}
Thanks!
Where have you seen {123=1}? It's not a standard representation in Scala, but it is the way Java defines toString for its Maps.
val sm = Map(1->1, 2->2) // Map(1 -> 1, 2 -> 2)
val jm = new java.util.HashMap[Int,Int]()
jm.put(1,1)
jm.put(2,2)
jm
// java.util.HashMap[Int,Int] = {1=1, 2=2}
-> is a method that creates tuples. By itself it doesn't directly have anything to do with maps. So for example 123 -> 1 returns a tuple (123, 1). You can try this in the REPL:
scala> 123 -> 1
res1: (Int, Int) = (123,1)
You can create a map by supplying tuples to object Map's apply method, which is what you are doing when you do this:
val m = Map(123 -> 1, 456 -> 2)
is the same as
val m = Map.apply(123 -> 1, 456 -> 2)
is the same as
val m = Map.apply((123, 1), (456, 2))
which creates a Map with two entries, one with key 123 and value 1, the other one with key 456 and value 2.