Related
By using Observer, I'm trying to build the code, which:
1.Generate some (random) values;
2.Combine this values;
3.If someone combined value exceed the threshold, the value have to be passed to another handler.
So I expect the resulted value to be returned for further usage
My code:
//generate
val o: Observable[Int] = Observable.repeatEval(Random.nextInt(10))
//handle
val f = o.foldLeft(0) { (acc, el) =>
if (acc < 15) {
el + acc
} else {
println("handled " + acc)
acc
}
}
//use handled
.flatMap{res =>
println("mapped " + res + 1)
Observable(res + 1)
}
But nothing passed to the flatMap-method.
The output is following for example:
0
3
7
11
12
handled 20
What am I doing wrong?
You want to use mapAccumulate + collect instead.
def groupWhile[A, B](o: Observable[A], s: B)(op: (B, A) => B)(predicate: B => Boolean): Observable[B] =
o.mapAccumulate(seed = s) {
case (b, a) =>
val bb = op(b, a)
if (predicate(bb)) (bb, None) else (s, Some(bb))
} collect {
case Some(b) => b
}
Use it like:
// Generate.
val o: Observable[Int] = Observable.repeatEval(Random.nextInt(10))
// Handle.
val f = groupWhile(o, 0)((acc, i) => acc + i)(r => r <= 15)
// Use handled.
f.mapEval { x =>
val res = x + 1
Task(println("Mapped: ${res}")).as(res)
}
As I always say, the Scaladoc is your friend.
This question already has answers here:
Scala foldLeft while some conditions are true
(6 answers)
Closed 2 years ago.
How optimize following code in good, functional way?
List(1,2,3,4,5).foldLeft(0) {
case (acc, e) =>
if(acc > 5) acc
else acc + e
}
It is of course simple example, I am asking for general way, how do not iterate all collection if we known that accumulator will not change
You can consider using #tailrec instead of foldLeft:
import scala.annotation.tailrec
#tailrec
def methodOption1(values: List[Int])(acc: Int): Int = {
if(acc > 5 || values.isEmpty) acc
else method(values.tail)(acc + values.head)
}
#tailrec
def methodOption2(values: List[Int])(sum: Int): Int = {
values match {
case Nil => sum
case _ if sum > 5 => sum
case e :: tail => method(tail)(sum + e)
}
}
methodOption1(List(1, 2, 3, 4, 5))(0)
methodOption2(List(1, 2, 3, 4, 5))(0)
You also can make Mapper to "view" it as .foldLeft
implicit class ListMapper[A](xs: List[A]) {
def foldLeftAsTailRecWithStop[B](z: B)(op: (B, A) => B)(stop: B => Boolean): B = {
#tailrec
def tailrec(xs: List[A])(acc: B): B = {
if(xs.isEmpty || stop(acc)) acc
else tailrec(xs.tail)(op(acc, xs.head))
}
tailrec(xs)(z)
}
def foldLeftAsTailRec[B](z: B)(op: (B, A) => B): B = {
#tailrec
def tailrec(xs: List[A])(acc: B): B = {
if(xs.isEmpty) acc
else tailrec(xs.tail)(op(acc, xs.head))
}
tailrec(xs)(z)
}
}
List(1, 2, 3,4,5).foldLeft(0)(_ + _)
List(1, 2, 3,4,5).foldLeftAsTailRec(0)(_ + _)
List(1, 2, 3,4,5).foldLeftAsTailRecWithStop(0)(_ + _)(_ > 5)
Outputs:
res0: Int = 15
res1: Int = 15
res2: Int = 6
You can use scanLeft(produces a lazy list containing cumulative results of applying the operator going left to right, including the initial value) and find (finds the first element of the lazy list satisfying a predicate, if any):
List(1,2,3,4,5)
.to(LazyList)
.scanLeft(0)(_ + _)
.find(_ > 5) // Some(6): Option[Int]
UPD
To tackle the issue raised by #jwvh in the comments I was able to come up only with this ugly design:
List(1,2,3,4,5)
.to(LazyList)
.scanLeft((0, 0))((t, c) => (t._1 + c, t._1)) // aggregate contains current and previous value
.takeWhile(t => (t._1 > 5 && t._2 <= 5) || t._1 <= 5)
.last._1
So I would say that writing custom tailrec function as in #Zvi Mints's answer should be a better option here.
I want to count the total amount of Class2 where Class2.b == 444. In this case, there are 4 of them.
object Main extends App {
class Class1(val a: Int)
class Class2(val b: Int)
val source = Seq[(Class1, Seq[Class2])](
(new Class1(1), Seq(new Class2(12), new Class2(2), new Class2(3), new Class2(4))),
(new Class1(2), Seq(new Class2(222), new Class2(22), new Class2(33), new Class2(444))),
(new Class1(3), Seq(new Class2(33), new Class2(444), new Class2(3), new Class2(14))),
(new Class1(4), Seq(new Class2(44), new Class2(444), new Class2(43), new Class2(444)))
)
// acc and item are Any!
val res = source fold(0) { (acc, item) => acc + item._2.count(_.b == 444) }
}
First error: you can't use point-free notation here:
val res = source.fold(0){ (acc, item) => acc + item._2.count(_.b == 444) }
<console>:10: error: value _2 is not a member of Any
val res = source.fold(0){ (acc, item) => acc + item._2.count(_.b == 444) }
^
Second error: fold method accepts supertype of elements type as the first parameter:
def fold[A1 >: A](z: A1)(op: (A1, A1) ⇒ A1): A1
In this case it's Any (common supertype of (Class1, Seq[Class2]) and Int).
You have to use foldLeft:
val res = source.foldLeft(0){ (acc, item) => acc + item._2.count(_.b == 444) }
//res: Int = 4
To use fold you have to convert elements of source to Int:
val res = source.map{ _._2.count(_.b == 444) }.fold(0){_ + _}
// res: Int = 4
Note that you could use sum instead of fold(0){_ + _}, you could also use view to avoid intermediate collection creation:
val res = source.view.map{ _._2.count(_.b == 444) }.sum
// res: Int = 4
Fold
Method fold is not the same as foldLeft. It's a special case of method aggregate:
scala> (1 to 4).par.fold(0){ (a, e) => println(a -> e); 0 }
(0,1)
(0,4)
(0,3)
(0,2)
(0,0)
(0,0)
(0,0)
fold for parallel collection splits collection into parts (Seq(1), Seq(2), Seq(3), Seq(4)), aggregates each part using operation {(a, e) => println(a -> e); 0}: (0,1), (0,2), (0,3), (0,4) and then aggregates results using the same operation: (0,0) 3 times.
In general (method aggregate) you have to provide different methods to aggregate each part and to combine results from different parts like this:
source.aggregate(0)( (acc, item) => acc + item._2.count(_.b == 444), _ + _ )
// Int = 4
I am actually blocked on this for about 4 hours now. I want to get a List of Pairs[String, Int] ordered by their int value. The function partiotion works fine, so should the bestN, but when loading this into my interpreter I get:
<console>:15: error: could not find implicit value for evidence parameter of type Ordered[T]
on my predicate. Does someone see what the problem is? I am really desperate at the moment...
This is the code:
def partition[T : Ordered](pred: (T)=>Boolean, list:List[T]): Pair[List[T],List[T]] = {
list.foldLeft(Pair(List[T](),List[T]()))((pair,x) => if(pred(x))(pair._1, x::pair._2) else (x::pair._1, pair._2))
}
def bestN[T <% Ordered[T]](list:List[T], n:Int): List[T] = {
list match {
case pivot::other => {
println("pivot: " + pivot)
val (smaller,bigger) = partition(pivot <, list)
val s = smaller.size
println(smaller)
if (s == n) smaller
else if (s+1 == n) pivot::smaller
else if (s < n) bestN(bigger, n-s-1)
else bestN(smaller, n)
}
case Nil => Nil
}
}
class OrderedPair[T, V <% Ordered[V]] (t:T, v:V) extends Pair[T,V](t,v) with Ordered[OrderedPair[T,V]] {
def this(p:Pair[T,V]) = this(p._1, p._2)
override def compare(that:OrderedPair[T,V]) : Int = this._2.compare(that._2)
}
Edit: The first function divides a List into two by applying the predicate to every member, the bestN function should return a List of the lowest n members of the list list. And the class is there to make Pairs comparable, in this case what I want do do is:
val z = List(Pair("alfred",1),Pair("peter",4),Pair("Xaver",1),Pair("Ulf",2),Pair("Alfons",6),Pair("Gulliver",3))
with this given List I want to get for example with:
bestN(z, 3)
the result:
(("alfred",1), ("Xaver",1), ("Ulf",2))
It looks like you don't need an Ordered T on your partition function, since it just invokes the predicate function.
The following doesn't work (presumably) but merely compiles. Other matters for code review would be the extra braces and stuff like that.
package evident
object Test extends App {
def partition[T](pred: (T)=>Boolean, list:List[T]): Pair[List[T],List[T]] = {
list.foldLeft(Pair(List[T](),List[T]()))((pair,x) => if(pred(x))(pair._1, x::pair._2) else (x::pair._1, pair._2))
}
def bestN[U,V<%Ordered[V]](list:List[(U,V)], n:Int): List[(U,V)] = {
list match {
case pivot::other => {
println(s"pivot: $pivot and rest ${other mkString ","}")
def cmp(a: (U,V), b: (U,V)) = (a: OrderedPair[U,V]) < (b: OrderedPair[U,V])
val (smaller,bigger) = partition(((x:(U,V)) => cmp(x, pivot)), list)
//val (smaller,bigger) = list partition ((x:(U,V)) => cmp(x, pivot))
println(s"smaller: ${smaller mkString ","} and bigger ${bigger mkString ","}")
val s = smaller.size
if (s == n) smaller
else if (s+1 == n) pivot::smaller
else if (s < n) bestN(bigger, n-s-1)
else bestN(smaller, n)
}
case Nil => Nil
}
}
implicit class OrderedPair[T, V <% Ordered[V]](tv: (T,V)) extends Pair(tv._1, tv._2) with Ordered[OrderedPair[T,V]] {
override def compare(that:OrderedPair[T,V]) : Int = this._2.compare(that._2)
}
val z = List(Pair("alfred",1),Pair("peter",4),Pair("Xaver",1),Pair("Ulf",2),Pair("Alfons",6),Pair("Gulliver",3))
println(bestN(z, 3))
}
I found the partition function hard to read; you need a function to partition all the parens. Here are a couple of formulations, which also use the convention that results accepted by the filter go left, rejects go right.
def partition[T](p: T => Boolean, list: List[T]) =
((List.empty[T], List.empty[T]) /: list) { (s, t) =>
if (p(t)) (t :: s._1, s._2) else (s._1, t :: s._2)
}
def partition2[T](p: T => Boolean, list: List[T]) =
((List.empty[T], List.empty[T]) /: list) {
case ((is, not), t) if p(t) => (t :: is, not)
case ((is, not), t) => (is, t :: not)
}
// like List.partition
def partition3[T](p: T => Boolean, list: List[T]) = {
import collection.mutable.ListBuffer
val is, not = new ListBuffer[T]
for (t <- list) (if (p(t)) is else not) += t
(is.toList, not.toList)
}
This might be closer to what the original code intended:
def bestN[U, V <% Ordered[V]](list: List[(U,V)], n: Int): List[(U,V)] = {
require(n >= 0)
require(n <= list.length)
if (n == 0) Nil
else if (n == list.length) list
else list match {
case pivot :: other =>
println(s"pivot: $pivot and rest ${other mkString ","}")
def cmp(x: (U,V)) = x._2 < pivot._2
val (smaller, bigger) = partition(cmp, other) // other partition cmp
println(s"smaller: ${smaller mkString ","} and bigger ${bigger mkString ","}")
val s = smaller.size
if (s == n) smaller
else if (s == 0) pivot :: bestN(bigger, n - 1)
else if (s < n) smaller ::: bestN(pivot :: bigger, n - s)
else bestN(smaller, n)
case Nil => Nil
}
}
Arrow notation is more usual:
val z = List(
"alfred" -> 1,
"peter" -> 4,
"Xaver" -> 1,
"Ulf" -> 2,
"Alfons" -> 6,
"Gulliver" -> 3
)
I suspect I am missing something, but I'll post a bit of code anyway.
For bestN, you know you can just do this?
val listOfPairs = List(Pair("alfred",1),Pair("peter",4),Pair("Xaver",1),Pair("Ulf",2),Pair("Alfons",6),Pair("Gulliver",3))
val bottomThree = listOfPairs.sortBy(_._2).take(3)
Which gives you:
List((alfred,1), (Xaver,1), (Ulf,2))
And for the partition function, you can just do this (say you wanted all pairs lower then 4):
val partitioned = listOfPairs.partition(_._2 < 4)
Which gives (all lower then 4 on the left, all greater on the right):
(List((alfred,1), (Xaver,1), (Ulf,2), (Gulliver,3)),List((peter,4), (Alfons,6)))
Just to share with you: this works! Thanks alot to all people who helped me, you're all great!
object Test extends App {
def partition[T](pred: (T)=>Boolean, list:List[T]): Pair[List[T],List[T]] = {
list.foldLeft(Pair(List[T](),List[T]()))((pair,x) => if(pred(x))(pair._1, x::pair._2) else (x::pair._1, pair._2))
}
def bestN[U,V<%Ordered[V]](list:List[(U,V)], n:Int): List[(U,V)] = {
list match {
case pivot::other => {
def cmp(a: (U,V), b: (U,V)) = (a: OrderedPair[U,V]) <= (b: OrderedPair[U,V])
val (smaller,bigger) = partition(((x:(U,V)) => cmp(pivot, x)), list)
val s = smaller.size
//println(n + " :" + s)
//println("size:" + smaller.size + "Pivot: " + pivot + " Smaller part: " + smaller + " bigger: " + bigger)
if (s == n) smaller
else if (s+1 == n) pivot::smaller
else if (s < n) bestN(bigger, n-s)
else bestN(smaller, n)
}
case Nil => Nil
}
}
class OrderedPair[T, V <% Ordered[V]](tv: (T,V)) extends Pair(tv._1, tv._2) with Ordered[OrderedPair[T,V]] {
override def compare(that:OrderedPair[T,V]) : Int = this._2.compare(that._2)
}
implicit final def OrderedPair[T, V <% Ordered[V]](p : Pair[T, V]) : OrderedPair[T,V] = new OrderedPair(p)
val z = List(Pair("alfred",1),Pair("peter",1),Pair("Xaver",1),Pair("Ulf",2),Pair("Alfons",6),Pair("Gulliver",3))
println(bestN(z, 3))
println(bestN(z, 4))
println(bestN(z, 1))
}
Is there a syntax in Scala that allows extractors to take a customization argument? This example is a bit contrived. Suppose I have a binary search tree on integers, and I want to match on the current node if its value is divisible by some custom value.
Using F# active patterns, I can do the following:
type Tree =
| Node of int * Tree * Tree
| Empty
let (|NodeDivisibleBy|_|) x t =
match t with
| Empty -> None
| Node(y, l, r) -> if y % x = 0 then Some((l, r)) else None
let doit = function
| NodeDivisibleBy(2)(l, r) -> printfn "Matched two: %A %A" l r
| NodeDivisibleBy(3)(l, r) -> printfn "Matched three: %A %A" l r
| _ -> printfn "Nada"
[<EntryPoint>]
let main args =
let t10 = Node(10, Node(1, Empty, Empty), Empty)
let t15 = Node(15, Node(1, Empty, Empty), Empty)
doit t10
doit t15
0
In Scala, I can do something similar, but not quite what I want:
sealed trait Tree
case object Empty extends Tree
case class Node(v: Int, l: Tree, r: Tree) extends Tree
object NodeDivisibleBy {
def apply(x: Int) = new {
def unapply(t: Tree) = t match {
case Empty => None
case Node(y, l, r) => if (y % x == 0) Some((l, r)) else None
}
}
}
def doit(t: Tree) {
// I would prefer to not need these two lines.
val NodeDivisibleBy2 = NodeDivisibleBy(2)
val NodeDivisibleBy3 = NodeDivisibleBy(3)
t match {
case NodeDivisibleBy2(l, r) => println("Matched two: " + l + " " + r)
case NodeDivisibleBy3(l, r) => println("Matched three: " + l + " " + r)
case _ => println("Nada")
}
}
val t10 = Node(10, Node(1, Empty, Empty), Empty)
val t15 = Node(15, Node(1, Empty, Empty), Empty)
doit(t10)
doit(t15)
It would be great if I could do:
case NodeDivisibleBy(2)(l, r) => println("Matched two: " + l + " " + r)
case NodeDivisibleBy(3)(l, r) => println("Matched three: " + l + " " + r)
but this is a compile time error: '=>' expected but '(' found.
Thoughts?
From the spec:
SimplePattern ::= StableId ‘(’ [Patterns] ‘)’
An extractor pattern x(p1, ..., pn) where n ≥ 0 is of the same
syntactic form as a constructor pattern. However, instead of a case
class, the stable identifier x denotes an object which has a member
method named unapply or unapplySeq that matches the pattern.
and:
A stable identifier is a path which ends in an identifier.
i.e., not an expression like NodeDivisibleBy(2).
So no, this isn't possible in any straightforward way in Scala, and personally I think that's just fine: having to write the following (which by the way I'd probably define in the NodeDivisibleBy object and import):
val NodeDivisibleBy2 = NodeDivisibleBy(2)
val NodeDivisibleBy3 = NodeDivisibleBy(3)
is a small price to pay for the increased readability of not having to decipher arbitrary expressions in the case clause.
As Travis Brown has noted, it's not really possible in scala.
What I do in that scenario is just separating the decomposition from the test with a guard and an alias.
val DivisibleBy = (n: Node, x: Int) => (n.v % x == 0)
def doit(t: Tree) = t match {
case n # Node(y, l, r) if DivisibleBy(n,2) => println("Matched two: " + l + " " + r)
case n # Node(y, l, r) if DivisibleBy(n,3) => println("Matched three: " + l + " " + r)
case _ => println("Nada")
}
Defining a separate DivisibleBy is obviously complete overkill in this simple case, but may help readability in more complex scenarios in a similar way as F# active patterns do.
You could also define divisibleBy as a method of Node and have:
case class Node(v: Int, l: Tree, r: Tree) extends Tree {
def divisibleBy(o:Int) = (v % o)==0
}
def doit(t: Tree) = t match {
case n # Node(y, l, r) if n divisibleBy 2 => println("Matched two: " + l + " " + r)
case n # Node(y, l, r) if n divisibleBy 3 => println("Matched three: " + l + " " + r)
case _ => println("Nada")
}
which I think is more readable (if more verbose) than the F# version
Bind together the case class, predicate and arguments, then match on the result as usual.
case class Foo(i: Int)
class Testable(val f: Foo, val ds: List[Int])
object Testable {
def apply(f: Foo, ds: List[Int]) = new Testable(f, ds)
def unapply(t: Testable): Option[(Foo, List[Int])] = {
val xs = t.ds filter (t.f.i % _ == 0)
if (xs.nonEmpty) Some((t.f, xs)) else None
}
}
object Test extends App {
val f = Foo(100)
Testable(f, List(3,5,20)) match {
case Testable(f, 3 :: Nil) => println(s"$f matched three")
case Testable(Foo(i), 5 :: Nil) if i < 50
=> println(s"$f matched five")
case Testable(f, ds) => println(s"$f matched ${ds mkString ","}")
case _ => println("Nothing")
}
}
Late answer, but there is a scalac plugin providing syntax ~(extractorWithParam(p), bindings), with all safety from compilation: https://github.com/cchantep/acolyte/tree/master/scalac-plugin#match-component
As I know answer is no.
I also use the previous way for this case.