Processing Set of Sets and return a flat Iterable - scala

val input=Set(Set("a","b"),Set("b","c"))
I want this:
Map("a"->1,"b"->2,"c"->1)
What is the best functional approach for implementing such functionality?
Using yield keyword results in nested Iterables:
output = for(firstlevel<-input) yield for(item<-firstlevel) yield item

update: incorporated the suggestion to use input.toSeq.flatten
instead of input.toSeq flatMap { _.toSeq }
convert to a single sequence of values...
input.toSeq.flatten
...group values that match...
input.toSeq.flatten groupBy { identity }
...and count
input.toSeq.flatten groupBy { identity } mapValues { _.size }

If you want to use for-comprehension and yield:
output = for{
(set,idx) <- input.zipWithIndex
item <- set
} yield (item -> idx)
The code in your last line can be simplified (but does not what you want):
output = for{
set <- input
item <- set
} yield item

Oh boy, that's so ugly...
input.foldLeft(Map[String,Int]())((m,s) =>
s.foldLeft(m)((n,t) => n + (t -> (1 + n.getOrElse(t,0)))))
[Edit]
The Collection-API needs really a method for "merging" two Maps (or did I just overlook it???), e.g.
def merge[A,B](m1: Map[A,B], m2:Map[A,B])(f: (B,B)=>B):Map[A,B] =
m1.foldLeft(m2)((m,t) =>
m + (t._1 -> m.get(t._1).map(k => f(k,t._2)).getOrElse(t._2)))
With this you could write something like:
input.map(_.map(x => x -> 1).toMap).reduceLeft(merge(_,_)(_+_))
[Edit2]
With Kevin's idea merge could be written as
def merge[A,B](m1: Map[A,B], m2:Map[A,B])(f: (B,B)=>B):Map[A,B] =
m1.keys ++ m2.keys map {k => k ->
List(m1.get(k), m2.get(k)).flatten.reduceLeft(f)} toMap
Seems like my Scala-Fu is still too weak. What's the best way to express
(o1,o2) match {
case (Some(x),Some(y)) => Some(f(x,y))
case (Some(x), _) => Some(x)
case (_, Some(y)) => Some(y)
case => error("crack in the time-space-continuum")
}
?

Related

scala using calculations from pattern matching's guard (if) in body

I'm using pattern matching in scala a lot. Many times I need to do some calculations in guard part and sometimes they are pretty expensive. Is there any way to bind calculated values to separate value?
//i wan't to use result of prettyExpensiveFunc in body safely
people.collect {
case ...
case Some(Right((x, y))) if prettyExpensiveFunc(x, y) > 0 => prettyExpensiveFunc(x)
}
//ideally something like that could be helpful, but it doesn't compile:
people.collect {
case ...
case Some(Right((x, y))) if {val z = prettyExpensiveFunc(x, y); y > 0} => z
}
//this sollution works but it isn't safe for some `Seq` types and is risky when more cases are used.
var cache:Int = 0
people.collect {
case ...
case Some(Right((x, y))) if {cache = prettyExpensiveFunc(x, y); cache > 0} => cache
}
Is there any better solution?
ps: Example is simplified and I don't expect anwers that shows that I don't need pattern matching here.
You can use cats.Eval to make expensive calculations lazy and memoizable, create Evals using .map and extract .value (calculated at most once - if needed) in .collect
values.map { value =>
val expensiveCheck1 = Eval.later { prettyExpensiveFunc(value) }
val expensiveCheck2 = Eval.later { anotherExpensiveFunc(value) }
(value, expensiveCheck1, expensiveCheck2)
}.collect {
case (value, lazyResult1, _) if lazyResult1.value > 0 => ...
case (value, _, lazyResult2) if lazyResult2.value > 0 => ...
case (value, lazyResult1, lazyResult2) if lazyResult1.value > lazyResult2.value => ...
...
}
I don't see a way of doing what you want without creating some implementation of lazy evaluation, and if you have to use one, you might as well use existing one instead of rolling one yourself.
EDIT. Just in case you haven't noticed - you aren't losing the ability to pattern match by using tuple here:
values.map {
// originial value -> lazily evaluated memoized expensive calculation
case a # Some(Right((x, y)) => a -> Some(Eval.later(prettyExpensiveFunc(x, y)))
case a => a -> None
}.collect {
// match type and calculation
...
case (Some(Right((x, y))), Some(lazyResult)) if lazyResult.value > 0 => ...
...
}
Why not run the function first for every element and then work with a tuple?
Seq(1,2,3,4,5).map(e => (e, prettyExpensiveFunc(e))).collect {
case ...
case (x, y) if y => y
}
I tried own matchers and effect is somehow OK, but not perfect. My matcher is untyped, and it is bit ugly to make it fully typed.
class Matcher[T,E](f:PartialFunction[T, E]) {
def unapply(z: T): Option[E] = if (f.isDefinedAt(z)) Some(f(z)) else None
}
def newMatcherAny[E](f:PartialFunction[Any, E]) = new Matcher(f)
def newMatcher[T,E](f:PartialFunction[T, E]) = new Matcher(f)
def prettyExpensiveFunc(x:Int) = {println(s"-- prettyExpensiveFunc($x)"); x%2+x*x}
val x = Seq(
Some(Right(22)),
Some(Right(10)),
Some(Left("Oh now")),
None
)
val PersonAgeRank = newMatcherAny { case Some(Right(x:Int)) => (x, prettyExpensiveFunc(x)) }
x.collect {
case PersonAgeRank(age, rank) if rank > 100 => println("age:"+age + " rank:" + rank)
}
https://scalafiddle.io/sf/hFbcAqH/3

Scala: Best way to remove tuples from Seq where one value is None

I wish to filter out None values where they appear in a Seq of tuples.
In the code below, I want to replace getOrElse with get. But then how do I remove the tuples where the first value is None ?
Here is my code. I feel it is inelegant.
myFirstMap.map {
case (key, value) =>
val tuple = (myLookUpMap.getOrElse(key,MyCaseClass("", None)), value.toString)
tuple
}.filter(_._1.name.nonEmpty).toIndexedSeq
}
What is the correct way to do this?
NOTE: this method will be called thousands of times on Seq with length 40 to 100, so performance is important
It looks like .map() and .flatMap() should do the trick, which is what a for comprehension is all about.
(for {
(k, v) <- myFirstMap
mcc <- myLookUpMap.get(k)
} yield (mcc, v.toString)).toIndexedSeq
myFirstMap.collect { case (k, _) if myFilterMap.contains(k) => myFilterMap(k)}
Maybe
myFirstMap.map {
case (key, value) =>
myLookUpMap.get(key).map( found => Tuple2( found, value.toString ) )
}.withFilter(_.nonEmpty).map( _.get ).toIndexedSeq
...or more readably...
val mbTuples = myFirstMap.map {
case (key, value) =>
myLookUpMap.get(key).map( found => Tuple2( found, value.toString ) )
}
val foundTuples = mbTuples.withFilter(_.nonEmpty).map( _.get )
val tupleSeq = foundTuples.toIndexedSeq
Or how about this approach:
val commonKeys = myFirstMap.keySet().intersect( myLookUpMap.keySet() )
val tupleSeq = commonKeys.map { case ( key, value ) =>
( myLookUpMap(key), value.toString )
}.toIndexedSeq
You can use flatMap to filter None in collection
myFirstMap.flatMap { case (key, value) => myLookUpMap.get(key).map(entity => (entity, value.toString)) }

Scala filter return only one (or specific number) of results

What is the best Scala idiomatic approach to verify that filter returns only one results (or specific amount in that matter), and if the amount correct, to continue with it?
For example:
val myFilteredListWithDesiredOneItem = unfilteredList
.filter(x => x.getId.equals(something))
.VERIFY AMOUNT
.toList
Consider this for a list of type T,
val myFilteredListWithDesiredOneItem = {
val xs = unfilteredList.filter(x => x.getId.equals(something))
if (xs.size == n) xs.toList
else List.empty[T]
}
Not a oneliner, the code remains simple none the less.
Try a match with guards, perhaps?
list.filter(...) match {
case Nil => // empty
case a if (a.size == 5) => // five items
case b#(List(item1, item2) => // two (explicit) items
case _ => // default
}
Something like this perhaps:
Option(list.filter(filterFunc))
.filter(_.size == n)
.getOrElse(throw new Exception("wrong size!"))

Split a list into a target element, and the rest of the list?

Let's say I have something like the following:
case class Thing(num: Int)
val xs = List(Thing(1), Thing(2), Thing(3))
What I'd like to do is separate the list into one particular value, and the rest of the list. The target value can be at any position in the list, or may not be present at all. The single value needs to be handled separately, after the other values are handled, so I can't simply use pattern matching.
What I have so far is this:
val (targetList, rest) = xs.partition(_.num == 2)
val targetEl = targetList match {
case x :: Nil => x
case _ => null
}
Is it possible to combine the two steps? Like
val (targetEl, rest) = xs.<some_method>
A note on handling order:
The reason that the target element must be handled last is that this is for use in a HTML template (Play framework). The other elements are looped through, and a HTML element is rendered for each. After that group of elements, another HTML element is created for the target element.
You can do it with pattern-matching in map, you just need multiple cases:
xs map {
case t # Thing(1) => // do something with thing 1
case t => // do something with the other things
}
To handle the OP's extra requirements:
xs map {
case t # Thing(num) if(num != 1) => // do something with things that are not "1"
case t => // do something with thing 1
}
Following produces two lists as tuples for some condition.
case class Thing(num: Int)
val xs = List(Thing(1), Thing(2), Thing(3))
val partioned = xs.foldLeft((List.empty[Thing], List.empty[Thing]))((x, y) => y match {
case t # Thing(1) => (x._1, t :: x._2)
case t => (t :: x._1, x._2)
})
//(List(Thing(3), Thing(2)),List(Thing(1)))
Try this:
val (targetEl, rest) = (xs.head, xs.tail)
It works for non-empty list. Nil case must be handled separately.
After some experimentation, I've come up with the following, which is almost what I'm looking for:
var (maybeTargetEl, rest) = xs
.foldLeft((Option.empty[Thing], List[Thing]())) { case ((opt, ls), x) =>
if (x.num == 1)
(Some(x), ls)
else
(opt, x :: ls)
}
The target value is still wrapped in a container, but at least it guarantees a single value.
After that I can do
rest map <some_method>
maybeTargetEl map <some_other_method>
If the order of the original list is important:
var (maybeTargetEl, rest) = xs.
foldLeft((Option.empty[Thing], ListBuffer[Thing]())){ case ((opt, lb), x) =>
if (x.num == 1)
(Some(x), ls)
else
(opt, lb += x)
} match {
case (opt, lb) => (opt, lb.toList)
}
#evanjdooner Your solution with fold works if target element is present only once. If you want to extract only one occurrence of target element:
def find(xs: List[T], target: T, prefix: List[T]) = xs match {
case target :: tail => (target, prefix ::: tail)
case other :: tail => find(tail, target, other :: prefix)
case Nil => throw new Exception("Not found")
}
val (el, rest) = find(xs, target, Nil)
Sorry, I can't add it as a comment.

zipWithIndex with and without case

How are the following 2 pieces of code equivalent? (how does case work)
list.zipWithIndex.flatMap{
rowAndIndex =>
rowAndIndex._1.zipWithIndex
}
and
list.zipWithIndex.flatMap {
case (rowAndIndex, r) =>
rowAndIndex.zipWithIndex
}
You are probably confused by wrong names in second sample. I changed it to:
list.zipWithIndex.flatMap {
case (row, index) =>
row.zipWithIndex
}
This is short version of:
list.zipWithIndex.flatMap { rowAndIndex =>
rowAndIndex match {
case (row, index) => row.zipWithIndex
}
}
I preferred the first one, since every element here is case (rowAndIndex, r), check it every time seems unnecessary.
And, it seems that you actually don't want the first 'index', why not just use:
list.map(s => s.zipWithIndex).flatten
By the way, I just put following code to http://scalass.com/tryout
val list = List("Abby", "Jim", "Tony")
val a = list.zipWithIndex.flatMap({a =>
a._1.zipWithIndex})
println(a)
val b = list.zipWithIndex.flatMap({case (rowAndIndex, r) =>
rowAndIndex.zipWithIndex})
println(b)
val d = list.map(s => s.zipWithIndex).flatten
println(d)
The output is all like
List((A,0), (b,1), (b,2), (y,3), (J,0), (i,1), (m,2), (T,0), (o,1), (n,2), (y,3))
This is what you want, right?