Very handy Ruby code:
some_map.each do |key,value|
# do something with key or value
end
Scala equivalent:
someMap.foreach( entry => {
val (key,value) = entry
// do something with key or value
})
Having to add the extra val line bugs me. I couldn't figure out how to state the function arg to extract the tuple, so I'm wondering is there a way to do this, or why is there no foreach that extracts the key and value for me?
This works, too:
someMap.foreach {case (key, value) =>
// do something with key and/or value
}
I like this one:
scala> val foo = Map( 1 -> "goo", 2 -> "boo" )
foo: scala.collection.immutable.Map[Int,java.lang.String] = Map(1 -> goo, 2 -> boo)
scala> for ((k,v) <- foo) println(k + " " + v)
1 goo
2 boo
You don't need even the val in for loop:
Following ViktorKlang's example:
scala> val foo = Map( 1 -> "goo", 2 -> "boo" )
foo: scala.collection.immutable.Map[Int,java.lang.String] = Map(1 -> goo, 2 -> boo)
scala> for ((k, v) <- foo) println(k + " " + v)
1 goo
2 boo
Note that for is rather powerful in Scala, so you can also use it for sequence comprehensions:
scala> val bar = for (val (k, v) <- foo) yield k
bar: Iterable[Int] = ArrayBuffer(1, 2)
Function.tupled converts a function (a1, a2) => b) to a function ((a1, a2)) => b.
import Function._
someMap foreach tupled((key, value) => printf("%s ==> %s\n", key, value))
Related
I'm trying to count occurences of letters in the Stream of strings, and then put maps for each string ( "letter"-> count) in the List.
def checksum(ipt: Stream[String]) = ipt.foldLeft(List(Map("x"->1)))( (n:
List[Map[String, Int]], m: String) => n ++
m.split("").groupBy(identity).mapValues(_.size).toMap)
It gives problem:
Expression of type List[Equals] doesn't conform to expected type List[Map[String, Int]]
What's wrong? Like there is no problem with doing it for each string:
def checksum(ipt: Stream[String]) = ipt.foreach( (m: String) => println(m.split("").groupBy(identity).mapValues(_.size)))
It gives something like that on
val s = "bababc"
val d = "abbcde"
checksum(List(s,d).toStream)
out:
Map(b -> 3, a -> 2, c -> 1)
Map(e -> 1, a -> 1, b -> 2, c -> 1, d -> 1)
But how do i stash all this maps in the List now? I can't use vars and need to do it in one expression.
if you need a map for each string, you can achieve it with a map function over the first stream as follows:
def checksums(ipt: Stream[String]): Stream[Map[Char, Int]] = {
ipt.map(checksum)
}
def checksum(ipt: String): Map[Char, Int] = ipt.foldLeft(Map.empty[Char, Int]) { case (acc, ch) =>
acc.get(ch) match {
case Some(q) => acc + (ch -> (q + 1))
case None => acc + (ch -> 1)
}
}
Going back to your code, the operator to add an element to a List is :+, not ++.
++ is used to concatenate lists.
So you can fix your code like this:
def checksumFixed(ipt: Stream[String]) = {
ipt.foldLeft(List(Map("x"->1))) { (n: List[Map[String, Int]], m: String) =>
n :+ m.split("").groupBy(identity).mapValues(_.length)
}
}
I am new to Scala I was trying to flatten the list and invert the mapping. For example I have a map as below :
Map("abc"->List(1,2,3),"def"->List(1,5,6))
I want the result to be :
Map(1->List("abc","def"),2->List("abc"),3->List("abc"),5->List("def"),6->List("def"))
What is the best way to achieve this?
scala> val mm = Map("abc"->List(1,2,3),"def"->List(1,5,6))
mm.toList.flatMap{ case (s, l) => l.map(ll => (ll, s))}.groupBy(_._1).map{ case (i, l) => (i, l.map(_._2))}
mm: scala.collection.immutable.Map[String,List[Int]] = Map(abc -> List(1, 2, 3), def -> List(1, 5, 6))
scala> res9: scala.collection.immutable.Map[Int,List[String]] = Map(5 -> List(def), 1 -> List(abc, def), 6 -> List(def), 2 -> List(abc), 3 -> List(abc))
scala>
UPDATE:
A slightly different solution I like better:
mm.toList.flatMap{ case (s, l) =>
l.map(li => (li, s))
}.foldLeft(Map.empty[Int, List[String]]){
case (m, (i, s)) => m.updated(i, s :: m.getOrElse(i, List.empty))
}
Here is how you can do in simple way
val data = Map("abc"->List(1,2,3),"def"->List(1,5,6))
val list = data.toList.flatMap(x => {
x._2.map(y => (y, x._1))
}).groupBy(_._1).map(x => (x._1, x._2.map(_._2)))
Output:
(5,List(def))
(1,List(abc, def))
(6,List(def))
(2,List(abc))
(3,List(abc))
Hope this helps!
Here is one more way of doing this:
Map("abc" -> List(1,2,3), "def"-> List(1,5,6)).flatMap {
case (key, values) => values.map(elem => Map(elem -> key))
}.flatten.foldRight(Map.empty[Int, List[String]]) { (elem, acc) =>
val (key, value) = elem
if (acc.contains(key)) {
val newValues = acc(key) ++ List(value)
(acc - key) ++ Map(key -> newValues)
} else {
acc ++ Map(key -> List(value))
}
}
So basically what I do is to go over the initial Map, transform that to a tuple and then do a foldRight and group identical keys into the accumulator.
This is a bit verbose than the other solutions posted here, but I prefer to avoid using underscores in my implementations as much as possible.
Another way to invert the Map:
val m = Map("abc" -> List(1, 2, 3), "def" -> List(1, 5, 6))
m.map{ case (k, v) => v.map((_, k)) }.flatten.
groupBy(_._1).mapValues( _.map(_._2) )
// res1: scala.collection.immutable.Map[Int,scala.collection.immutable.Iterable[String]] = Map(
// 5 -> List(def), 1 -> List(abc, def), 6 -> List(def), 2 -> List(abc), 3 -> List(abc)
// )
In Scala Map (see API) what is the difference in semantics and performance between mapValues and transform ?
For any given map, for instance
val m = Map( "a" -> 2, "b" -> 3 )
both
m.mapValues(_ * 5)
m.transform( (k,v) => v * 5 )
deliver the same result.
Let's say we have a Map[A,B]. For clarification: I'm always referring to an immutable Map.
mapValues takes a function B => C, where C is the new type for the values.
transform takes a function (A, B) => C, where this C is also the type for the values.
So both will result in a Map[A,C].
However with the transform function you can influence the result of the new values by the value of their keys.
For example:
val m = Map( "a" -> 2, "b" -> 3 )
m.transform((key, value) => key + value) //Map[String, String](a -> a2, b -> b3)
Doing this with mapValues will be quite hard.
The next difference is that transform is strict, whereas mapValues will give you only a view, which will not store the updated elements. It looks like this:
protected class MappedValues[C](f: B => C) extends AbstractMap[A, C] with DefaultMap[A, C] {
override def foreach[D](g: ((A, C)) => D): Unit = for ((k, v) <- self) g((k, f(v)))
def iterator = for ((k, v) <- self.iterator) yield (k, f(v))
override def size = self.size
override def contains(key: A) = self.contains(key)
def get(key: A) = self.get(key).map(f)
}
(taken from https://github.com/scala/scala/blob/v2.11.2/src/library/scala/collection/MapLike.scala#L244)
So performance-wise it depends what is more effective. If f is expensive and you only access a few elements of the resulting map, mapValues might be better, since f is only applied on demand. Otherwise I would stick to map or transform.
transform can also be expressed with map. Assume m: Map[A,B] and f: (A,B) => C, then
m.transform(f) is equivalent to m.map{case (a, b) => (a, f(a, b))}
collection.Map doesn't provide transform: it has a different signature for mutable and immutable Maps.
$ scala
Welcome to Scala version 2.11.2 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_11).
Type in expressions to have them evaluated.
Type :help for more information.
scala> val im = Map('a -> 1, 'b -> 2, 'c -> 3)
im: scala.collection.immutable.Map[Symbol,Int] = Map('a -> 1, 'b -> 2, 'c -> 3)
scala> im.mapValues(_ * 7) eq im
res0: Boolean = false
scala> im.transform { case (k,v) => v*7 } eq im
res2: Boolean = false
scala> val mm = collection.mutable.Map('a -> 1, 'b -> 2, 'c -> 3)
mm: scala.collection.mutable.Map[Symbol,Int] = Map('b -> 2, 'a -> 1, 'c -> 3)
scala> mm.mapValues(_ * 7) eq mm
res3: Boolean = false
scala> mm.transform { case (k,v) => v*7 } eq mm
res5: Boolean = true
Mutable transform mutates in place:
scala> mm.transform { case (k,v) => v*7 }
res6: mm.type = Map('b -> 98, 'a -> 49, 'c -> 147)
scala> mm.transform { case (k,v) => v*7 }
res7: mm.type = Map('b -> 686, 'a -> 343, 'c -> 1029)
So mutable transform doesn't change the type of the map:
scala> im mapValues (_ => "hi")
res12: scala.collection.immutable.Map[Symbol,String] = Map('a -> hi, 'b -> hi, 'c -> hi)
scala> mm mapValues (_ => "hi")
res13: scala.collection.Map[Symbol,String] = Map('b -> hi, 'a -> hi, 'c -> hi)
scala> mm.transform { case (k,v) => "hi" }
<console>:9: error: type mismatch;
found : String("hi")
required: Int
mm.transform { case (k,v) => "hi" }
^
scala> im.transform { case (k,v) => "hi" }
res15: scala.collection.immutable.Map[Symbol,String] = Map('a -> hi, 'b -> hi, 'c -> hi)
...as can happen when constructing a new map.
Here's a couple of unmentioned differences:
mapValues creates a Map that is NOT serializable, without any indication that it's just a view (the type is Map[_, _], but just try to send one across the wire).
Since mapValues is just a view, every instance contains the real Map - which could be another result of mapValues. Imagine you have an actor with some state, and every mutation of the state sets the new state to be a mapValues on the previous state...in the end you have deeply nested maps with a copy of each previous state of the actor (and, yes, both of these are from experience).
What's the idiomatic way to call map over a collection producing 0 or 1 result per entry?
Suppose I have:
val data = Array("A", "x:y", "d:e")
What I'd like as a result is:
val target = Array(("x", "y"), ("d", "e"))
(drop anything without a colon, split on colon and return tuples)
So in theory I think I want to do something like:
val attempt1 = data.map( arg => {
arg.split(":", 2) match {
case Array(l,r) => (l, r)
case _ => (None, None)
}
}).filter( _._1 != None )
What I'd like to do is avoid the need for the any-case and get rid of the filter.
I could do this by pre-filtering (but then I have to test the regex twice):
val attempt2 = data.filter( arg.contains(":") ).map( arg => {
val Array(l,r) = arg.split(":", 2)
(l,r)
})
Last, I could use Some/None and flatMap...which does get rid of the need to filter, but is it what most scala programmers would expect?
val attempt3 = data.flatMap( arg => {
arg.split(":", 2) match {
case Array(l,r) => Some((l,r))
case _ => None
}
})
It seems to me like there'd be an idiomatic way to do this in Scala, is there?
With a Regex extractor and collect :-)
scala> val R = "(.+):(.+)".r
R: scala.util.matching.Regex = (.+):(.+)
scala> Array("A", "x:y", "d:e") collect {
| case R(a, b) => (a, b)
| }
res0: Array[(String, String)] = Array((x,y), (d,e))
Edit:
If you want a map, you can do:
scala> val x: Map[String, String] = Array("A", "x:y", "d:e").collect { case R(a, b) => (a, b) }.toMap
x: Map[String,String] = Map(x -> y, d -> e)
If performance is a concern, you can use collection.breakOut as shown below to avoid creation of an intermediate array:
scala> val x: Map[String, String] = Array("A", "x:y", "d:e").collect { case R(a, b) => (a, b) } (collection.breakOut)
x: Map[String,String] = Map(x -> y, d -> e)
Quite a few functions on Map take a function on a key-value tuple as the argument. E.g. def foreach(f: ((A, B)) ⇒ Unit): Unit. So I looked for a short way to write an argument to foreach:
> val map = Map(1 -> 2, 3 -> 4)
map: scala.collection.immutable.Map[Int,Int] = Map(1 -> 2, 3 -> 4)
> map.foreach((k, v) => println(k))
error: wrong number of parameters; expected = 1
map.foreach((k, v) => println(k))
^
> map.foreach({(k, v) => println(k)})
error: wrong number of parameters; expected = 1
map.foreach({(k, v) => println(k)})
^
> map.foreach(case (k, v) => println(k))
error: illegal start of simple expression
map.foreach(case (k, v) => println(k))
^
I can do
> map.foreach(_ match {case (k, v) => println(k)})
1
3
Any better alternatives?
You were very close with map.foreach(case (k, v) => println(k)). To use case in an anonymous function, surround it by curly brackets.
map foreach { case (k, v) => println(k) }
In such cases I often use the for syntax.
for ((k,v) <- map) println(k)
According to Chapter 23 in "Programming in Scala" the above for loop is translated to call foreach.
One alternative is the tupled method of the Function object:
import Function.tupled;
// map tupled foreach {(k, v) => println(k)}
map foreach tupled {(k, v) => println(k)}
You can also access a tuple as follows:
scala> val map = Map(1 -> 2, 3 -> 4)
map: scala.collection.immutable.Map[Int,Int] = Map((1,2), (3,4))
scala> map foreach (t => println(t._1))
1
3
Welcome to Scala version 2.8.0.Beta1-prerelease (OpenJDK Server VM, Java 1.6.0_0).
Type in expressions to have them evaluated.
Type :help for more information.
scala> val m = Map('a -> 'b, 'c -> 'd)
m: scala.collection.immutable.Map[Symbol,Symbol] = Map('a -> 'b, 'c -> 'd)
scala> m foreach { case(k, v) => println(k) }
'a
'c
I was pretty close with the last attempt, actually:
> map.foreach({case (k, v) => println(k)})
1
3