Is there a "for" syntax for flatmap? - scala

Is there a "for" syntax for
c flatmap ( x => d flatmap (y => f(x,y) ) )
?
Because I've used Haskell in the past, I keep expecting the "for" syntax in Scala to mimic the "do" syntax of Haskell. This is probably an unrealistic expectation. In Haskell which I could write
do x <- c
y <- d
f(x, y)

You could also map the last result on itself.
Using the same example as dhg:
val c = 1 to 3
val d = 4 to 6
def f(x: Int, y: Int) = Vector(x,y)
for {
x <- c
y <- d
z <- f(x, y)
} yield z
// Vector(1, 4, 1, 5, 1, 6, 2, 4, 2, 5, 2, 6, 3, 4, 3, 5, 3, 6)
Which corresponds to:
c flatMap ( x => d flatMap (y => f(x,y) map (identity) ) )

You can just flatten the result:
val c = 1 to 3
val d = 4 to 6
def f(x: Int, y: Int) = Vector(x,y)
c flatMap ( x => d flatMap (y => f(x,y) ) )
// Vector(1, 4, 1, 5, 1, 6, 2, 4, 2, 5, 2, 6, 3, 4, 3, 5, 3, 6)
(for { x <- c; y <- d } yield f(x,y)).flatten
// Vector(1, 4, 1, 5, 1, 6, 2, 4, 2, 5, 2, 6, 3, 4, 3, 5, 3, 6)
Presumably this is a much less frequently used case since it is necessarily less common that the output of the for is flattenable. And sticking .flatten on the end is pretty easy, so having a special syntax for it seems unnecessarily complicated.

Flattening may impact performance but i think scalac is clever enough to encode
for {
x <- c
y <- d
z <- f(x,y)
} yield z
into
c flatMap { x => d flatMap { y => f(x,y) } }
This is annoying that the 'for' syntax is not as convenient as the 'do'-notation (writing _ <- someExpression instead of just someExpression in a for feels my heart with sadness).

Related

Scala, why can't underscore function syntax infer type?

I'm new to scala and I've stumbled upon some weird cases where type inference does not work as expected. for example, this does not compile:
List(1, 2, 3, 4, 5, 6)
.map(if _ > 3 then "foo" else "bar")
the compiler explicitly states it can't infer the type of _$1 which I take to be the first parameter of the function the syntax above desugars to.
somewhat frustratingly, the below code compiles just fine, even with no type annotation:
List(1, 2, 3, 4, 5, 6)
.map{ n => if n > 3 then "foo" else "bar"}
clearly there's something I'm not grasping about how _ desugars. can somebody clue me in on what's missing?
You are missing parenthesis:
List(1, 2, 3, 4, 5, 6)
.map(if (_) > 3 then "foo" else "bar")
See it working for Scala 3.
Or more "canonical" version working both for Scala 3 and Scala 2 and mentioned in Scala 2.11 spec:
placeholder syntax.
equivalent anonymous function
_ + 1
x => x + 1
_ * _
(x1, x2) => x1 * x2
(_: Int) * 2
(x: Int) => (x: Int) * 2
if (_) x else y
z => if (z) x else y
_.map(f)
x => x.map(f)
_.map( _ + 1)
x => x.map(y => y + 1)
List(1, 2, 3, 4, 5, 6)
.map(_ > 3)
.map(if (_) "foo" else "bar")

How to sum two neighbours in a list in scala

If you have one Integer list in Scala, and you want to iterate through it and sum every two neighbours with the same value and return this as a list, how would one do that ?
So for example:
List(4, 4, 2, 6) => List(8, 2, 6)
I'm completely new to Scala, but I can imagine that pattern match or map could be useful.
def sumSameNeighbours: List[Int] => List[Int] = {
ls match {
case l1::l2:ls => l1 == l2
}
}
This is what I can think of.
EDIT: How would I have to change the code in order to iterate from right to left instead from left to right?
So that f.e. it would be:
List(2, 2, 2, 6, 4) => List(2, 4, 6, 4)
instead of
List(2, 2, 2, 6, 4) => List(4, 2, 6, 4)
This is pretty close to your suggestion and seems basically to work:
import scala.annotation.tailrec
def sumSameNeighbors( ls : List[Int] ) : List[Int] = {
#tailrec
def walk( unsummed : List[Int], reverseAccum : List[Int] ) : List[Int] = {
unsummed match {
case a :: b :: rest if a == b => walk( rest, a + b :: reverseAccum )
case a :: rest => walk( rest, a :: reverseAccum )
case Nil => reverseAccum.reverse
}
}
walk( ls, Nil )
}
Note: Based on final OP's specifications clarification, this answer doesn't exactly fit the question requirements.
Here is a solution using List.grouped(2):
list.grouped(2).toList
.flatMap {
case List(a, b) if a == b => List(a + b)
case l => l
}
The idea is to group consecutive elements by pair. If the pair has the same elements, we return their sum to be flatMaped and otherwise both elements untouched.
List(4, 4, 2, 6) => List(8, 2, 6)
List(2, 4, 4, 2, 6) => List(2, 4, 4, 2, 6)
List(2) => List(2)
List(9, 4, 4, 4, 2, 6) => List(9, 4, 8, 2, 6)
Another way using foldRight, which I find a good default for this sort of traversing a collection while creating a new one:
list.foldRight(List.empty[Int]) {
case (x, y :: tail) if x == y => (x + y) :: tail
case (x, list) => x :: list
}
Output of List(2, 2, 2, 6, 4) is List(2, 4, 6, 4) as requested.
The main thing I wasn't clear on from your examples is what the output should be if summing creates new neighbours: should List(8, 4, 2, 2) turn into List(8, 4, 4) or List(16)? This produces the second.

Abstract over repeated flatMap

I am trying to generalize repeated, nested flatMap but not sure if one exists.
The following code will produce all combinations of n choose 3, :
def choose3flatMap(n: Int, r: Int = 3) =
(0 to n - r)
.flatMap(i => (i + 1 to n - (r - 1))
.flatMap(j => (j + 1 to n - (r - 2))
.map(k => Seq(i, j, k))))
Repeating the flatMap operation, we can get all combinations of n choose 5, :
def choose5flatMap(n: Int, r: Int = 5) =
(0 to n - r)
.flatMap(i => (i + 1 to n - (r - 1))
.flatMap(j => (j + 1 to n - (r - 2))
.flatMap(k => (k + 1 to n - (r - 3))
.flatMap(l => (l + 1 to n - (r - 4))
.map(m => Seq(i, j, k, l, m)))))
Clearly there is a pattern here. I would like to utilize this similarity to get a general solution for n choose r, . Is there a simple way to accomplish this. Perhaps a higher order function of some sort?
What I have tried:
Scala lets me rewrite the map/flatMap with a for expression. This reads cleaner, but the number of choices in still hard-coded.
def choose3Loop(n: Int, r: Int = 3) =
for {
i <- 0 to n - r
j <- i + 1 to n - (r - 1)
k <- j + 1 to n - (r - 2)
} yield Seq(i, j, k)
I can write a recursive solution directly using flatMap or utilizing the sugar of a for expression:
def combinationsRecursive(n: Int, r: Int, i: Int = 0): Seq[Seq[Int]] =
if (r == 1) (i until n).map(Seq(_))
else {
(i to n - r).flatMap(
i => combinationsRecursive(n, r - 1, i + 1).map(j => i +: j))
}
def combinationsRecursiveLoop(n: Int, r: Int, i: Int = 0): Seq[Seq[Int]] =
if (r == 1) (i until n).map(Seq(_))
else
for {
i <- i to n - r
j <- combinationsRecursiveLoop(n, r - 1, i + 1)
} yield i +: j
While these are solutions to the general problem, I wonder if there is a higher-level abstraction I am missing here that may be applicable to other problems as well. I recognize that for this particular application, I could do (0 to n).combinations(r) to use a library-provided implementation of computing combinations.
While the above code is Scala, in this case I am interested the functional programming aspect of it and not the language capabilities. If there is a solution but one that is not supported by Scala I am interested in that.
Edit: He is a sample caller and the resulting output by request:
scala> combinationsRecursiveLoop(5, 3)
res0: Seq[Seq[Int]] = Vector(List(0, 1, 2), List(0, 1, 3), List(0, 1, 4), List(0, 2, 3), List(0, 2, 4), List(0, 3, 4), List(1, 2, 3), List(1, 2, 4), List(1, 3, 4), List(2, 3, 4))
scala> combinationsRecursiveLoop(5, 3).map("("+_.mkString(", ")+")").mkString(" ")
res1: String = (0, 1, 2) (0, 1, 3) (0, 1, 4) (0, 2, 3) (0, 2, 4) (0, 3, 4) (1, 2, 3) (1, 2, 4) (1, 3, 4) (2, 3, 4)
It just provides all r-element subsets of the set of integers starting at zero containing n elements. More information on combinations can be found on Wikipedia.
Here is one way to look at this, that I have come up with.
You can extract one stage in your chain as a function f: List[Int] => List[List[Int]], that takes a List with a beginning of a combination, and prepends all possible next elements to it.
For example in choose(5, 3), f(List(2, 0)) would result in List(List(3, 2, 0), List(4, 2, 0)).
Here is a possible implementation of such a function with some processing for the initial case added:
val f: List[Int] => List[List[Int]] = l =>
(l.headOption.map(_ + 1).getOrElse(0) to n - (r - l.size))
.map(_ :: l).toList
Now, such a function is a Kleisli arrow Kleisli[List, List[Int], List[Int]], and it's endomorphic (has the same argument and return types).
There is a monoid instance for endomorphic kleisli arrows, where the monoid "addition" means the flatMap operation (or in pseudocode, f1 |+| f2 == a => f1(a).flatMap(f2)). So to replace your chain of flatMaps you need to "add" r instances of this f function, or in other words to multiply the f function by r.
This idea translates directly into Scalaz code:
import scalaz._, Scalaz._
def choose(n: Int, r: Int) = {
val f: List[Int] => List[List[Int]] = l =>
(l.headOption.map(_ + 1).getOrElse(0) to n - (r - l.size))
.map(_ :: l).toList
Endomorphic.endoKleisli(f).multiply(r).run(Nil)
}
And here is an example running it:
scala> choose(4, 3)
res1: List[List[Int]] = List(List(2, 1, 0), List(3, 1, 0), List(3, 2, 0), List(3, 2, 1))
The combinations are reversed, but it should be possible to make a version, that produces combinations with elements in the increasing order (or just run choose(n, r).map(_.reverse)).
Another improvement would be to make a lazy version, that returns Stream[List[Int]] (or even better a scalaz.EphemeralStream[List[Int]]: you don't want to have all the combinations cached in memory), but this is left as an exercise to the reader.

Scala tuple of collections instead of collection of tuples

In one invocation to map we construct a collection of tuples, for instance like this,
val a = (1 to 5).map { x => (x, x*10) }
a: Vector((1,10), (2,20), (3,30), (4,40), (5,50))
and then we extract the first and second elements into two separate, immutable collections
val b1 = a.map {_._1}
b1: Vector(1, 2, 3, 4, 5)
val b2 = a.map {_._2}
b2: Vector(10, 20, 30, 40, 50)
How to obtain b1 and b2 by iterating over the initial collection once only,
val (b1,b2) = (1 to 5).map { x => /* ??? */ }
Use unzip:
scala> (1 to 5).unzip { x => x -> x * 3 }
res0: (Vector(1, 2, 3, 4, 5),Vector(3, 6, 9, 12, 15))
Note that IonuČ› G. Stan's answer is the same as:
(1 to 5).unzip{ x => (x, x * 3)}
which makes how to get triples of collections back even clearer:
(1 to 5).unzip3{ x => (x, x * 3, x * 10)}

Scala trying to count instances of a digit in a number

This is my first day using scala. I am trying to make a string of the number of times each digit is represented in a string. For instance, the number 4310227 would return "1121100100" because 0 appears once, 1 appears once, 2 appears twice and so on...
def pow(n:Int) : String = {
val cubed = (n * n * n).toString
val digits = 0 to 9
val str = ""
for (a <- digits) {
println(a)
val b = cubed.count(_==a.toString)
println(b)
}
return cubed
}
and it doesn't seem to work. would like some scalay reasons why and to know whether I should even be going about it in this manner. Thanks!
When you iterate over strings, which is what you are doing when you call String#count(), you are working with Chars, not Strings. You don't want to compare these two with ==, since they aren't the same type of object.
One way to solve this problem is to call Char#toString() before performing the comparison, e.g., amend your code to read cubed.count(_.toString==a.toString).
As Rado and cheeken said, you're comparing a Char with a String, which will never be be equal. An alternative to cheekin's answer of converting each character to a string is to create a range from chars, ie '0' to '9':
val digits = '0' to '9'
...
val b = cubed.count(_ == a)
Note that if you want the Int that a Char represents, you can call char.asDigit.
Aleksey's, Ren's and Randall's answers are something you will want to strive towards as they separate out the pure solution to the problem. However, given that it's your first day with Scala, depending on what background you have, you might need a bit more context before understanding them.
Fairly simple:
scala> ("122333abc456xyz" filter (_.isDigit)).foldLeft(Map.empty[Char, Int]) ((histo, c) => histo + (c -> (histo.getOrElse(c, 0) + 1)))
res1: scala.collection.immutable.Map[Char,Int] = Map(4 -> 1, 5 -> 1, 6 -> 1, 1 -> 1, 2 -> 2, 3 -> 3)
This is perhaps not the fastest approach because intermediate datatype like String and Char are used but one of the most simplest:
def countDigits(n: Int): Map[Int, Int] =
n.toString.groupBy(x => x) map { case (n, c) => (n.asDigit, c.size) }
Example:
scala> def countDigits(n: Int): Map[Int, Int] = n.toString.groupBy(x => x) map { case (n, c) => (n.asDigit, c.size) }
countDigits: (n: Int)Map[Int,Int]
scala> countDigits(12345135)
res0: Map[Int,Int] = Map(5 -> 2, 1 -> 2, 2 -> 1, 3 -> 2, 4 -> 1)
Where myNumAsString is a String, eg "15625"
myNumAsString.groupBy(x => x).map(x => (x._1, x._2.length))
Result = Map(2 -> 1, 5 -> 2, 1 -> 1, 6 -> 1)
ie. A map containing the digit with its corresponding count.
What this is doing is taking your list, grouping the values by value (So for the initial string of "15625", it produces a map of 1 -> 1, 2 -> 2, 6 -> 6, and 5 -> 55.). The second bit just creates a map of the value to the count of how many times it occurs.
The counts for these hundred digits happen to fit into a hex digit.
scala> val is = for (_ <- (1 to 100).toList) yield r.nextInt(10)
is: List[Int] = List(8, 3, 9, 8, 0, 2, 0, 7, 8, 1, 6, 9, 9, 0, 3, 6, 8, 6, 3, 1, 8, 7, 0, 4, 4, 8, 4, 6, 9, 7, 4, 6, 6, 0, 3, 0, 4, 1, 5, 8, 9, 1, 2, 0, 8, 8, 2, 3, 8, 6, 4, 7, 1, 0, 2, 2, 6, 9, 3, 8, 6, 7, 9, 5, 0, 7, 6, 8, 7, 5, 8, 2, 2, 2, 4, 1, 2, 2, 6, 8, 1, 7, 0, 7, 6, 9, 5, 5, 5, 3, 5, 8, 2, 5, 1, 9, 5, 7, 2, 3)
scala> (new Array[Int](10) /: is) { case (a, i) => a(i) += 1 ; a } map ("%x" format _) mkString
warning: there were 1 feature warning(s); re-run with -feature for details
res7: String = a8c879caf9
scala> (new Array[Int](10) /: is) { case (a, i) => a(i) += 1 ; a } sum
warning: there were 1 feature warning(s); re-run with -feature for details
res8: Int = 100
I was going to point out that no one used a char range, but now I see Kristian did.
def pow(n:Int) : String = {
val cubed = (n * n * n).toString
val cnts = for (a <- '0' to '9') yield cubed.count(_ == a)
(cnts map (c => ('0' + c).toChar)).mkString
}