What type of expression is this in scala? - scala

Considering x,p,r are evaluated from the previous expressions , what is happening underneath , <- and then after =
val a = for{
x <- y
p = q (x)
r <- s (p)
} yield (something(p.something, r.something))

The <- is equivalent (syntactic sugar) to .flatMap call, while = is equivalent to val x = (and yield kind of final .map).
So the code is equivalent to:
val a = y.flatMap { x => // first <-
val p = q (x)
s(p).map { r => // 2nd <- + yield
something(p.something, r.something)
}
}

Related

How to yield multiple values?

I have a for comprehension like:
val ao = Option(1)
val bo = Option(2)
val (x,y) = for (a <- ao; b <- bo) yield (a+b, b+a*2)
However this does not work. For comprehension returns Option[(Int,Int)] but cannot be assigned to individual x and y.
If I do:
val Some((x,y)) = for ...
It causes exception when yield None.
How to achieve this goal? I want x and y to be Option[Int]. I hope to find an elegant solution without using like x._1 or x.getOrElse, or match
It should have been unzip, but unfortunately, unzip returns Lists, not Options. Probably the shortest work-around would be:
val pairOpt = for (a <- ao; b <- bo) yield (a+b, b+a*2)
val (x, y) = (pairOpt.map(_._1), pairOpt.map(_._2))
Isn't pattern matching the best way to handle options?
val res = for (a <- ao; b <- bo) yield (a+b, b+a*2)
val (x, y) = res match {
case Some((x, y)) => (Some(x), Some(y))
case None => (None, None)
}
Why would that not be considered 'elegant'?

SCALA: Generating a list of Tuple2 objects meeting some criteria

I want to generate a list of Tuple2 objects. Each tuple (a,b) in the list should meeting the conditions:a and b both are perfect squares,(b/30)<a<b
and a>N and b>N ( N can even be a BigInt)
I am trying to write a scala function to generate the List of Tuples meeting the above requirements?
This is my attempt..it works fine for Ints and Longs..But for BigInt there is sqrt problem I am facing..Here is my approach in coding as below:
scala> def genTups(N:Long) ={
| val x = for(s<- 1L to Math.sqrt(N).toLong) yield s*s;
| val y = x.combinations(2).map{ case Vector(a,b) => (a,b)}.toList
| y.filter(t=> (t._1*30/t._2)>=1)
| }
genTups: (N: Long)List[(Long, Long)]
scala> genTups(30)
res32: List[(Long, Long)] = List((1,4), (1,9), (1,16), (1,25), (4,9), (4,16), (4,25), (9,16), (9,25), (16,25))
Improved this using BigInt square-root algorithm as below:
def genTups(N1:BigInt,N2:BigInt) ={
def sqt(n:BigInt):BigInt = {
var a = BigInt(1)
var b = (n>>5)+BigInt(8)
while((b-a) >= 0) {
var mid:BigInt = (a+b)>>1
if(mid*mid-n> 0) b = mid-1
else a = mid+1
}; a-1 }
val x = for(s<- sqt(N1) to sqt(N2)) yield s*s;
val y = x.combinations(2).map{ case Vector(a,b) => (a,b)}.toList
y.filter(t=> (t._1*30/t._2)>=1)
}
I appreciate any help to improve in my algorithm .
You can avoid sqrt in you algorithm by changing the way you calculate x to this:
val x = (BigInt(1) to N).map(x => x*x).takeWhile(_ <= N)
The final function is then:
def genTups(N: BigInt) = {
val x = (BigInt(1) to N).map(x => x*x).takeWhile(_ <= N)
val y = x.combinations(2).map { case Vector(a, b) if (a < b) => (a, b) }.toList
y.filter(t => (t._1 * 30 / t._2) >= 1)
}
You can also re-write this as a single chain of operations like this:
def genTups(N: BigInt) =
(BigInt(1) to N)
.map(x => x * x)
.takeWhile(_ <= N)
.combinations(2)
.map { case Vector(a, b) if a < b => (a, b) }
.filter(t => (t._1 * 30 / t._2) >= 1)
.toList
In a quest for performance, I came up with this recursive version that appears to be significantly faster
def genTups(N1: BigInt, N2: BigInt) = {
def sqt(n: BigInt): BigInt = {
var a = BigInt(1)
var b = (n >> 5) + BigInt(8)
while ((b - a) >= 0) {
var mid: BigInt = (a + b) >> 1
if (mid * mid - n > 0) {
b = mid - 1
} else {
a = mid + 1
}
}
a - 1
}
#tailrec
def loop(a: BigInt, rem: List[BigInt], res: List[(BigInt, BigInt)]): List[(BigInt, BigInt)] =
rem match {
case Nil => res
case head :: tail =>
val a30 = a * 30
val thisRes = rem.takeWhile(_ <= a30).map(b => (a, b))
loop(head, tail, thisRes.reverse ::: res)
}
val squares = (sqt(N1) to sqt(N2)).map(s => s * s).toList
loop(squares.head, squares.tail, Nil).reverse
}
Each recursion of the loop adds all the matching pairs for a given value of a. The result is built in reverse because adding to the front of a long list is much faster than adding to the tail.
Firstly create a function to check if number if perfect square or not.
def squareRootOfPerfectSquare(a: Int): Option[Int] = {
val sqrt = math.sqrt(a)
if (sqrt % 1 == 0)
Some(sqrt.toInt)
else
None
}
Then, create another func that will calculate this list of tuples according to the conditions mentioned above.
def generateTuples(n1:Int,n2:Int)={
for{
b <- 1 to n2;
a <- 1 to n1 if(b>a && squareRootOfPerfectSquare(b).isDefined && squareRootOfPerfectSquare(a).isDefined)
} yield ( (a,b) )
}
Then on calling the function with parameters generateTuples(5,10)
you will get an output as
res0: scala.collection.immutable.IndexedSeq[(Int, Int)] = Vector((1,4), (1,9), (4,9))
Hope that helps !!!

Merging list of uneven length with default value for missing matches

Im trying to pair up two lists in Scala where non matching pairs should be replaced by a default value, this is what I have so far but thy all fall short in some way.
How do I create List((a,a),(b,empty),(c,c))???
case class Test(id: Option[Int] = None)
val empty = Test()
val a = Test(Some(1))
val b = Test(Some(2))
val c = Test(Some(3))
val cache = List(a,b,c)
val delta = List(a,c)
//Trial 1
val newCache1 = cache.zipAll(delta,empty,empty)
//Tial 2
val newCache2 = for {
c <- cache
d <- delta
if c.id == d.id
} yield (c,d)
//Tial 3
val newCache3 = for {
c <- cache
d <- delta
} yield if (c.id == d.id) (c,d) else (c,empty)
Turn your delta into a map, then join them up.
val deltaMap: Map[Int, Test] =
delta.flatMap(x => x.id.map(id => id -> x)).toMap
val newCache: Seq[(Test, Test)] = cache.map { c =>
c -> c.id.flatMap(deltaMap.get).getOrElse(empty)
}

Scala - can 'for-yield' clause yields nothing for some condition?

In Scala language, I want to write a function that yields odd numbers within a given range. The function prints some log when iterating even numbers. The first version of the function is:
def getOdds(N: Int): Traversable[Int] = {
val list = new mutable.MutableList[Int]
for (n <- 0 until N) {
if (n % 2 == 1) {
list += n
} else {
println("skip even number " + n)
}
}
return list
}
If I omit printing logs, the implementation become very simple:
def getOddsWithoutPrint(N: Int) =
for (n <- 0 until N if (n % 2 == 1)) yield n
However, I don't want to miss the logging part. How do I rewrite the first version more compactly? It would be great if it can be rewritten similar to this:
def IWantToDoSomethingSimilar(N: Int) =
for (n <- 0 until N) if (n % 2 == 1) yield n else println("skip even number " + n)
def IWantToDoSomethingSimilar(N: Int) =
for {
n <- 0 until N
if n % 2 != 0 || { println("skip even number " + n); false }
} yield n
Using filter instead of a for expression would be slightly simpler though.
I you want to keep the sequentiality of your traitement (processing odds and evens in order, not separately), you can use something like that (edited) :
def IWantToDoSomethingSimilar(N: Int) =
(for (n <- (0 until N)) yield {
if (n % 2 == 1) {
Option(n)
} else {
println("skip even number " + n)
None
}
// Flatten transforms the Seq[Option[Int]] into Seq[Int]
}).flatten
EDIT, following the same concept, a shorter solution :
def IWantToDoSomethingSimilar(N: Int) =
(0 until N) map {
case n if n % 2 == 0 => println("skip even number "+ n)
case n => n
} collect {case i:Int => i}
If you will to dig into a functional approach, something like the following is a good point to start.
First some common definitions:
// use scalaz 7
import scalaz._, Scalaz._
// transforms a function returning either E or B into a
// function returning an optional B and optionally writing a log of type E
def logged[A, E, B, F[_]](f: A => E \/ B)(
implicit FM: Monoid[F[E]], FP: Pointed[F]): (A => Writer[F[E], Option[B]]) =
(a: A) => f(a).fold(
e => Writer(FP.point(e), None),
b => Writer(FM.zero, Some(b)))
// helper for fixing the log storage format to List
def listLogged[A, E, B](f: A => E \/ B) = logged[A, E, B, List](f)
// shorthand for a String logger with List storage
type W[+A] = Writer[List[String], A]
Now all you have to do is write your filtering function:
def keepOdd(n: Int): String \/ Int =
if (n % 2 == 1) \/.right(n) else \/.left(n + " was even")
You can try it instantly:
scala> List(5, 6) map(keepOdd)
res0: List[scalaz.\/[String,Int]] = List(\/-(5), -\/(6 was even))
Then you can use the traverse function to apply your function to a list of inputs, and collect both the logs written and the results:
scala> val x = List(5, 6).traverse[W, Option[Int]](listLogged(keepOdd))
x: W[List[Option[Int]]] = scalaz.WriterTFunctions$$anon$26#503d0400
// unwrap the results
scala> x.run
res11: (List[String], List[Option[Int]]) = (List(6 was even),List(Some(5), None))
// we may even drop the None-s from the output
scala> val (logs, results) = x.map(_.flatten).run
logs: List[String] = List(6 was even)
results: List[Int] = List(5)
I don't think this can be done easily with a for comprehension. But you could use partition.
def getOffs(N:Int) = {
val (evens, odds) = 0 until N partition { x => x % 2 == 0 }
evens foreach { x => println("skipping " + x) }
odds
}
EDIT: To avoid printing the log messages after the partitioning is done, you can change the first line of the method like this:
val (evens, odds) = (0 until N).view.partition { x => x % 2 == 0 }

Help me get this for comprehension right

I have the following (working) code
val superSuperSorts = superSorts.flatMap(relations.get(_)).flatMap(x=>x)
And I give you the types here
val superSorts: Set[Sort]
val relations: Map[Sort, Set[Sort]]
Changing it to this for-comprehension gives me a compile error
val superSuperSorts =
for(
ss <- superSorts;
sss <- relations.get(ss); //get Option[Set[Sort]] and flatten the option
s <- sss //extract the elements from the Set
) yield s
of this reading
error: type mismatch;
found : scala.collection.immutable.Set[edu.uulm.scbayes.logic.Sort]
required: Option[?]
s <- sss
Please explain why my for-comprehension is wrong.
You can't flatMap an Option. Have a look at its type signature:
def flatMap [B] (f: (A) ⇒ Option[B]): Option[B]
So, flatMap unpacks the Option, but requires a new Option, so you need an alternative. You can use the method getOrElse of Map or method seq of Option:
val superSuperSorts = for {
s <- superSorts
ss <- relations.getOrElse(s, Set.empty)
} yield s
val superSuperSorts = for {
s <- superSorts
ss <- relations.get(s).seq
sss <- ss
} yield sss
Another problem is, that your flatMap code is not equivalent with your for-expression. The expression
for (x <- expr1; y <- expr2) yield expr3
is translated to
expr1.flatMap(x => for (y <- expr2) yield expr3)
and in another step to
expr1.flatMap(x => expr2.map(y => expr3))
But you have:
expr1.flatMap(x => expr2).flatMap(y => expr3)
Let me give an example to make clear where the problem is. Let's say you have:
val superSorts = Set('x)
val relations = Map('x -> Set('a, 'b))
This code:
val superSuperSorts =
for(
ss <- superSorts;
sss <- relations.get(ss); //get Option[Set[Sort]] and flatten the option
s <- sss //extract the elements from the Set
) yield s
translates to:
superSorts.flatMap(
ss => relations.get(ss).flatMap(
sss => sss.map(
s => s)))
First, note that the last term is a map, not a flatMap. Now, let's consider an iteration with the data above:
ss = 'x
sss = Set('a, 'b)
s = 'a, 'b
And now let's go backward in the code.
// Set('a, 'b) => Set('a, 'b)
sss.map(s => s)
// Some(Set('a, 'b)) => Some('a, 'b)????
relations.get(ss).flatMap(...)
See the problem here? How can an Option[Set[Sort]] be flattened? There's no such a thing as a Some('a, 'b).
So, why does the original code work?
val superSuperSorts = superSorts.flatMap(relations.get(_)).flatMap(x=>x)
If we break it down:
// Set('x) => Set(Set('a, 'b))
superSorts.flatMap(relations.get(_))
// Set(Set('a, 'b')) => Set('a, 'b)
(...).flatMap(x=>x)
See how all the flatMap are being applied over a Set, not an Option? The Option was eliminated by the flatMap and never came into play.
The more-or-less equivalent for-comprehension for your code would be:
val superSuperSorts = for {
x <- (for {
ss <- superSorts
sss <- relations.get(ss)
} yield sss)
s <- x
} yield s
This introduces a couple of identity maps: map(sss => sss) and map(s => s), which get around the fact that the last generator in a for-comprehension is always a map.
It's important to understand that a for comprehension will yield the type of collection fed in. So why your code didn't work is you want to return a single element(s). Try this:
val superSuperSorts =
  for(
  ss <- superSorts;
  sss <- relations.get(ss); //get Option[Set[Sort]] and flatten the option
) yield sss
:/ Hope this helps