How to traverse with scalaz - scala

I've tried to simplify a real code but not to much.
Given the following input, implementation of f and g are just for examples, real one are more complicated
scala> val m = Map("a" -> 1, "b" -> 2, "c" -> 3, "d" -> 4)
m: scala.collection.immutable.Map[String,Int] = Map(a -> 1, b -> 2, c -> 3, d -> 4)
scala> val f : Int => Option[Int] = i => if (i % 2 == 0) Some(i) else None
f: Int => Option[Int] = <function1>
scala> val g = (a:Int, l:List[Int]) => a :: l
g: (Int, List[Int]) => List[Int] = <function2>
Here is the process :
m.foldLeft(List[Int]()) { case (l, (k, v)) =>
f(v) match {
case Some(w) => g(w, l)
case None => l
}
}
Is it possible to use scalaz to better reveal the intent ?
I'm thinkink about m.traverseS

If g really needs to handle the whole List[Int] then I immediately thought of Endo (requires slightly rewriting g):
val f: Int => Iterable[Int] = ???
val g: Int => Endo[List[Int]] = ???
val m = Map("a" -> 1, "b" -> 2, "c" -> 3, "d" -> 4)
Foldable[List].fold(m.values.toList flatMap f map g).apply(List[Int]())
I'm not sure that's much clearer though.

m.collect{ case(s, i) => (s, f(i))}
.filter{ case (s,i) => i.isDefined }
.toList
.traverseS({s => State({ l: List[Int] => (g(s._2.get, l), ())})})
.run(Nil)
._1
.reverse

Related

Reverse a Map which has A Set as its value using HOF

I am trying to reverse a map that has a String as the key and a set of numbers as its value
My goal is to create a list that contains a tuple of a number and a list of strings that had the same number in the value set
I have this so far:
def flipMap(toFlip: Map[String, Set[Int]]): List[(Int, List[String])] = {
toFlip.flatMap(_._2).map(x => (x, toFlip.keys.toList)).toList
}
but it is only assigning every String to every Int
val map = Map(
"A" -> Set(1,2),
"B" -> Set(2,3)
)
should produce:
List((1, List(A)), (2, List(A, B)), (3, List(B)))
but is producing:
List((1, List(A, B)), (2, List(A, B)), (3, List(A, B)))
This works to, but it's not exactly what you might need and you may need some conversions to get the exact data type you need:
toFlip.foldLeft(Map.empty[Int, Set[String]]) {
case (acc, (key, numbersSet)) =>
numbersSet.foldLeft(acc) {
(updatingMap, newNumber) =>
updatingMap.updatedWith(newNumber) {
case Some(existingSet) => Some(existingSet + key)
case None => Some(Set(key))
}
}
}
I used Set to avoid duplicate key insertions in the the inner List, and used Map for better look up instead of the outer List.
You can do something like this:
def flipMap(toFlip: Map[String, Set[Int]]): List[(Int, List[String])] =
toFlip
.toList
.flatMap {
case (key, values) =>
values.map(value => value -> key)
}.groupMap(_._1)(_._2)
.view
.mapValues(_.distinct)
.toList
Note, I personally would return a Map instead of a List
Or if you have cats in scope.
def flipMap(toFlip: Map[String, Set[Int]]): Map[Int, Set[String]] =
toFlip.view.flatMap {
case (key, values) =>
values.map(value => Map(value -> Set(key)))
}.toList.combineAll
// both scala2 & scala3
scala> map.flatten{ case(k, s) => s.map(v => (k, v)) }.groupMapReduce{ case(k, v) => v }{case(k, v) => List(k)}{ _ ++ _ }
val res0: Map[Int, List[String]] = Map(1 -> List(A), 2 -> List(A, B), 3 -> List(B))
// scala3 only
scala> map.flatten((k, s) => s.map(v => (k, v))).groupMapReduce((k, v) => v)((k, v) => List(k))( _ ++ _ )
val res1: Map[Int, List[String]] = Map(1 -> List(A), 2 -> List(A, B), 3 -> List(B))

Inverting mapping from list elements to to String in Scala

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

Using filterNot with a Map

I have a simple map
val m = Map("a1" -> "1", "b2" -> "2", "c3" -> "3")
val someList = List("b", "d")
m.filterNot( (k,v) => someList.exist(l => k.startsWith(l)) )
I'm getting an error:
error: missing parameter type
I'm doing something silly here I'm sure, why isn' this compiling?
filterNot needs a case keyword and {} when you extract k, v from tuple.
note that its not exist its exists
m.filterNot { case (k,v) => someList.exists(l => k.startsWith(l)) }
or
m.filterNot(pair => someList.exists(l => pair._1.startsWith(l)))
Explanation
As you are extracting k, v from the tuple using extractor syntax you have to use case keyword and {}
Without extractor syntax you can do
m.filterNot(pair => someList.exists(l => pair._1.startsWith(l)))
Scala REPL
scala> val m = Map("a1" -> "1", "b2" -> "2", "c3" -> "3")
m: scala.collection.immutable.Map[String,String] = Map(a1 -> 1, b2 -> 2, c3 -> 3)
scala> val someList = List("b", "d")
someList: List[String] = List(b, d)
scala> m.filterNot { case (k,v) => someList.exists(l => k.startsWith(l)) }
res15: scala.collection.immutable.Map[String,String] = Map(a1 -> 1, c3 -> 3)
Without extractor syntax
Now you need not use case keyword and {} as we are not using extracting the key and value using extractor syntax
scala> m.filterNot(pair => someList.exists(l => pair._1.startsWith(l)))
res18: scala.collection.immutable.Map[String,String] = Map(a1 -> 1, c3 -> 3)
scala> val m = Map("a1" -> "1", "b2" -> "2", "c3" -> "3")
m: scala.collection.immutable.Map[String,String] = Map(a1 -> 1, b2 -> 2, c3 -> 3)
scala> val someList = List("b", "d")
someList: List[String] = List(b, d)
scala> m.filterNot(pair => someList.exists(l => pair._1.startsWith(l)))
res19: scala.collection.immutable.Map[String,String] = Map(a1 -> 1, c3 -> 3)
The issue is this: the filterNot method accepts one parameter, while you are defining a list of two parameters. This confuses the compiler and that message is the result.
In order to solve it, you can use the following syntax (notice the usage of pattern matching with the case keyword):
m.filterNot { case (k,v) => someList.exist(l => k.startsWith(l)) }
Using the pattern matching like this creates a PartialFunction that will be decompose key and value and be applied like a normal function to your Map.
Using for comprehension syntax, extraction and filtering may be achieved as follows,
for ( pair#(k,v) <- m; l <- someList if !k.startsWith(l)) yield pair

How to split an iterator based on a condition on prev and curr elements?

I want to split a list of elements into a list of lists such that neighboring elements in the inner list satisfy a given condition.
A simple condition would be neighboring elements are equal. Then if the input is List(1,1,1,2,2,3,3,3,3) output is List(List(1,1,1),List(2,2),List(3,3,3)).
Another condition could be current element should be greater than prev element. Then if the input is List(1,2,3,1,4,6,5,7,8), the output is List(List(1,2,3), List(1,4,6), List(5,7,8)). It would also be wonderful if the method can act on Iterator. The typedef of the method is
def method[A](lst:List[A], cond:(A,A)=>Boolean):List[List[A]]
def method[A](lst:Iterator[A], cond:(A,A)=>Boolean):Iterator[Iterator[A]]
You can use sliding together with span in a recursive function for the desired effect. This quick and dirty version is less efficient, but terser than some of the alternative:
def method[A](lst: TraversableOnce[A], cond: (A, A) => Boolean): List[List[A]] = {
val iterable = lst.toIterable
iterable.headOption.toList.flatMap { head =>
val (next, rest) = iterable.sliding(2).filter(_.size == 2).span(x => cond(x.head, x.last))
(head :: next.toList.map(_.last)) :: method(rest.map(_.last), cond)
}
}
If you want to lazily execute the code, you can return an Iterator[List[A]] instead of List[List[A]]:
def method[A](lst: TraversableOnce[A], cond: (A, A) => Boolean): Iterator[List[A]] = {
val iterable = lst.toIterable
iterable.headOption.toIterator.flatMap { head =>
val (next, rest) = iterable.sliding(2).filter(_.size == 2).span(x => cond(x.head, x.last))
Iterator(head :: next.toList.map(_.last)) ++ method(rest.map(_.last), cond)
}
}
And you can verify that this is lazy:
val x = (Iterator.range(0, 10) ++ Iterator.range(3, 5) ++ Iterator.range(1, 3)).map(x => { println(x); x })
val iter = method(x, (x: Int, y: Int) => x < y) //Only prints 0-9, and then 3!
iter.take(2).toList //Prints more
iter.toList //Prints the rest
You can make it even lazier by returning an Iterator[Iterator[A]]:
def method[A](lst: TraversableOnce[A], cond: (A, A) => Boolean): Iterator[Iterator[A]] = {
val iterable = lst.toIterable
iterable.headOption.toIterator.flatMap { head =>
val (next, rest) = iterable.sliding(2).filter(_.size == 2).span(x => cond(x.head, x.last))
Iterator(Iterator(head) ++ next.toIterator.map(_.last)) ++ method(rest.map(_.last), cond)
}
}
As a relatively unrelated side note, when you have generic parameters of this form, you're better off using 2 parameter lists:
def method[A](lst: TraversableOnce[A])(cond: (A, A) => Boolean)
When you have 2 parameter lists like this, the type inference can be a little bit smarter:
//No need to specify parameter types on the anonymous function now!
method(List(1, 3, 2, 3, 4, 1, 8, 1))((x, y) => x < y).toList
//You can now even use underscore anonymous function notation!
method(List(1, 4, 2, 3, 4, 1, 8))(_ < _)
Here is something close (I believe) to what you are asking for. The only issue with this is that it always produces a List of Lists for the result as opposed to being based on the input type:
val iter = Iterator(1,1,2,2,2,3,3,3)
val list = List(4,5,5,5,5,6,6)
def same(a:Int,b:Int) = a == b
def gt(a:Int, b:Int) = b > a
println(groupByPred(iter, same))
println(groupByPred(list, gt))
def groupByPred[L <: TraversableOnce[T], T](trav:L, cond:(T,T) => Boolean):List[List[T]] = {
val (ret, inner) =
trav.foldLeft((List.empty[List[T]], List.empty[T])){
case ((acc, list), el) if list.isEmpty || cond(list.head, el) => (acc,el :: list)
case ((acc, list), el) => (list.reverse :: acc,el :: List.empty)
}
(inner.reverse :: ret).reverse
}
If you run that code, the output should be the following:
List(List(1, 1), List(2, 2, 2), List(3, 3, 3))
List(List(4, 5), List(5), List(5), List(5, 6), List(6))
Try this.
Puts the head of the list as the first element of the first element of the List of Lists. Then adds things to that first List if the condition holds. If it doesn't, starts a new List with the current entry as the first element.
Both the inner list and the outer are constructed in the wrong order. So reverse each element of the outer List (with map) and then reverse the outer list.
val xs = List(1, 1, 1, 2, 2, 3, 3, 3, 3)
val ys = List(1, 2, 3, 1, 4, 6, 5, 7, 8)
def method[A](lst: List[A], cond: (A, A) => Boolean): List[List[A]] = {
lst.tail.foldLeft(List(List(lst.head))) { (acc, e) =>
if (cond(acc.head.head, e))
(e :: acc.head) :: acc.tail
else List(e) :: acc
}.map(_.reverse).reverse
}
method(xs, { (a: Int, b: Int) => a == b })
//> res0: List[List[Int]] = List(List(1, 1, 1), List(2, 2), List(3, 3, 3, 3))
method(ys, { (a: Int, b: Int) => a < b })
//> res1: List[List[Int]] = List(List(1, 2, 3), List(1, 4, 6), List(5, 7, 8))
Iterator overload
def method[A](iter:Iterator[A], cond: (A, A) => Boolean): List[List[A]] = {
val h = iter.next
iter.foldLeft(List(List(h))) { (acc, e) =>
if (cond(acc.head.head, e))
(e :: acc.head) :: acc.tail
else List(e) :: acc
}.map(_.reverse).reverse
}
method(xs.toIterator, { (a: Int, b: Int) => a == b })
//> res0: List[List[Int]] = List(List(1, 1, 1), List(2, 2), List(3, 3, 3, 3))
method(ys.toIterator, { (a: Int, b: Int) => a < b })
//> res1: List[List[Int]] = List(List(1, 2, 3), List(1, 4, 6), List(5, 7, 8))
More generic version (hat-tip to #cmbaxter for some ideas here) that works with Lists, Iterators and anything that can be traversed once:
def method[A, T <: TraversableOnce[A]](trav: T, cond: (A, A) => Boolean)
: List[List[A]] = {
trav.foldLeft(List(List.empty[A])) { (acc, e) =>
if (acc.head.isEmpty || !cond(acc.head.head, e)) List(e) :: acc
else (e :: acc.head) :: acc.tail
}.map(_.reverse).reverse
}

Difference between mapValues and transform in Map

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