From a Set of Booleans, how to return Tuple containing number that are true, number that are false? - scala

I'm pretty new of Scala, and I know there must be a nice way to do this, but I can't come up with something nice and readable.
I have a set of ids (strings), and for each id, I run some function that returns a boolean.
The result is a Set[Boolean], but I want to create a tuple containing two numbers, one is the number of true and one is the number of false.
What's a clean/readable way to do this?

Given your ids and f:
val ids: Set[String] = ???
def f(s: String): Boolean = ???
The following gets you there fairly concisely using the built-in partition function:
val (trues, falses) = ids partition f
(trues.size, falses.size)

You can utilize the count method of a Seq:
val ids: Seq[String] = Seq("1", "12", "3")
def containsOne(s: String) = s.contains('1')
val processedIds = ids.map(containsOne)
// first item is amount of trues, second is amount of falses
val count: (Int, Int) = (processedIds.count(identity), processedIds.count(_ == false))
You must use a Seq as a Set will 'flatten' out the collection of Boolean (to a maximum size of 2, no duplicates allowed).

Here's an expression that counts the number of even elements and odd elements in the set:
Set(3,4,5,6,8,3).toSeq.map{_ % 2 == 0}
.foldLeft((0,0)){(t,c) => if (c) (t._1+1, t._2) else (t._1, t._2+1)}
The toSeq is necessary to keep the output of map from being just a Set.
Just replace {_ % 2 == 0} with a call to your function.

Given your fn,
scala> def fn(x: String) = x.contains("customer")
fn: (x: String)Boolean
you have to .map to create boolean -> Set(Id), then aggregate by boolean, then count how many IDs for each boolean
scala> Set("customerId-1", "customerId-2", "id-3", "id-4")
.map(x => fn(x) -> x)
.groupBy(_._1)
.map { case (boolean, set) => boolean -> set.size }
res51: scala.collection.immutable.Map[Boolean,Int] = Map(false -> 2, true -> 2)

Here's my attempt at a one-liner (except that it doesn't fit on one line in this little box:(
My test function is true if division by 3 leaves a remainder of 1, and false otherwise, and I'm running it on the range 1 to 6 (i.e., 1,2,3,4,5):
scala> val x = (1 to 6).partition(_%3 == 1) match
| { case (s1,s2) => (s1.length, s2.length) }
x: (Int, Int) = (2,4)
And so, writing the main function in a little more generality,
scala> def boolCounter[T](
| s: Seq[T],
| f: T => Boolean): (Integer, Integer) =
| s.partition(f) match { case (s1, s2) => (s1.length, s2.length) }
boolCounter: [T](s: Seq[T], f: T => Boolean)(Integer, Integer)
scala> val r = 1 to 6
r: scala.collection.immutable.Range.Inclusive = Range 1 to 6
scala> val f: Int => Boolean = { x => x%3 == 1}
f: Int => Boolean = $$Lambda$1252/1891031939#5a090f62
scala> boolCounter(r, f)
res0: (Integer, Integer) = (2,4)

Related

How to get max and min values of an Array of Tuples

Say I have a List of Tuples of Integers
var i = Array(1->3, 5->9, 15->18)
How can I return a Tuple of the highest and lowest values from the above?
So for the above input, 1-> 18 should be returned as 1 is the lowest and 18 is the highest value. Here's the skeleton of the function that takes an Array of Tuples and returns the highest & the lowest values as a Tuple.
def returnHighest(i: Array[(Int, Int)]): (Int, Int)={
....
}
Lot's of ways to do this of course. Here is one:
val i = Array(1->3, 5->9, 15->18)
i: Array[(Int, Int)] = Array((1,3), (5,9), (15,18))
scala> val flatI = i.flatMap{case(a,b) => List(a, b)}
flatI: Array[Int] = Array(1, 3, 5, 9, 15, 18)
scala> flatI.min -> flatI.max
res3: (Int, Int) = (1,18)
You could use foldLeft, but you need to be careful about the start value. What if the array is empty ?
val res4 = Array(1->3, 5->9, 15->18)
res4.foldLeft(res4(0))({
case (acc, i) =>
Math.min(acc._1, i._1) -> Math.max(acc._2, i._2)
})
res6: (Int, Int) = (1, 18)

fold left operation in Scala?

I am having difficulty understanding how fold left works in Scala.
The following code computes for each unique character in the list chars the number of
times it occurs. For example, the invocation
times(List('a', 'b', 'a'))
should return the following (the order of the resulting list is not important):
List(('a', 2), ('b', 1))
def times(chars: List[Char]): List[(Char, Int)] = {
def incr(acc: Map[Char,Int], c: Char) = {
val count = (acc get c).getOrElse(0) + 1
acc + ((c, count));
}
val map = Map[Char, Int]()
(map /: chars)(incr).iterator.toList
}
I am just confused as to what the last line of this function is actually doing?
Any help wpuld be great.
Thanks.
foldLeft in scala works like this:
suppose you have a list of integers,
val nums = List(2, 3, 4, 5, 6, 7, 8, 9, 10)
val res= nums.foldLeft(0)((m: Int, n: Int) => m + n)
you will get res=55.
lets visualise it.
val res1 = nums.foldLeft(0) { (m: Int, n: Int) => println("m: " + m + " n: " + n);
m + n }
m: 0 n: 1
m: 1 n: 2
m: 3 n: 3
m: 6 n: 4
m: 10 n: 5
m: 15 n: 6
m: 21 n: 7
m: 28 n: 8
m: 36 n: 9
m: 45 n: 10
so, we can see that we need to pass initial accumulator value in foldLeft argument. And accumulated value is stored in 'm' and next value we get in 'n'.
And finally we get the accumulator as result.
Let's start from the "last line" which you are asking about: as the Map trait extends Iterable which in turn extends Traversable where the operator /: is explained, the code (map /: chars)(incr) does fold-left over chars, with the initial value of the accumulator being the empty mapping from characters to integers, applying incr to each intermediate value of acc and each element c of chars.
For example, when chars is List('a', 'b', 'a', 'c'), the fold-left expression (map /: chars)(incr) equals incr(incr(incr(incr(Map[Char, Int](), 'a'), 'b'), 'a'), 'c').
Now, as for what incr does: it takes an intermediate mapping acc from characters to integers, along with a character c, and increments by 1 the integer corresponding to c in the mapping. (Strictly speaking, the mapping is immutable and therefore never mutated: instead, a new, updated mapping is created and returned. Also, getOrElse(0) says that, if c does not exist in acc, the integer to be incremented is considered 0.)
As a whole, given List('a', 'b', 'a', 'c') as chars for example, the final mapping would be List(('a', 2), ('b', 1), ('c', 1)) when converted to a list by toList.
I rewrote your function in a more verbose way:
def times(chars: List[Char]): List[(Char, Int)] = {
chars
.foldLeft(Map[Char, Int]()){ (acc, c) =>
acc + ((c, acc.getOrElse(c, 0) + 1))
}
.toList
}
Let's see the first steps on times("aba".toList)
First invocation:
(Map(), 'a') => Map() ++ Map(`a` -> 1)
Second invocation:
(Map(`a` -> 1), `b`) => Map('a' -> 1) ++ Map('b' ->1)
Third invocation:
(Map('a' -> 1, 'b' ->1), 'a') =>
Map('a' -> 1, 'b' ->1) ++ Map('a' -> 2) =>
Map('a' -> 2, 'b' ->1)
The actual implementation in the scala codebase is very concise:
def foldLeft[B](z: B)(f: (B, A) => B): B = {
var acc = z
var these = this
while (!these.isEmpty) {
acc = f(acc, these.head)
these = these.tail
}
acc
}
Let me rename stuff for clarity:
def foldLeft[B](initialValue: B)(f: (B, A) => B): B = {
//Notice that both accumulator and collectionCopy are `var`s! They are reassigned each time in the loop.
var accumulator = initialValue
//create a copy of the collection
var collectionCopy = this //the function is inside a collection class, so **this** is the collection
while (!collectionCopy.isEmpty) {
accumulator = f(accumulator , collection.head)
collectionCopy = these.tail
}
accumulator
}
Edit after comment:
Let us revisit now the the OPs function and rewrite it in an imperative manner (i.e. non-functional, which apparently is the source of confusion):
(map /: chars)(incr) is be exactly equivalent to chars.foldLeft(map)(incr), which can be imperatively rewritten as:
def foldLeft(initialValue: Map[Char,Int])(incrFunction: (Map[Char,Int], Char) => Map[Char,Int]): Map[Char,Int] = {
//Notice that both accumulator and charList are `var`s! They are reassigned each time in the loop.
var accumulator = initialValue
//create a copy of the collection
var charList: List[Char] = this //the function is inside a collection class, so **this** is the collection
while (!charList.isEmpty) {
accumulator = incrFunction(accumulator , collection.head)
charList = these.tail
}
accumulator
}
I hope this makes the concept of foldLeft clearer.
So it is essentially an abstraction over an imperative while loop, that accumulates some value by traversing the collection and updating the accumulator. The accumulator is updated using a user-provided function that takes the previous value of the accumulator and the current item of the collection.
Its very description hints that it is a great tool to compute all sorts of aggregates on a collection, like sum, max etc. Yeah, scala collections actually provide all these functions, but they serve as a good example use case.
On the specifics of your question, let me point out that this can be easily done using groupBy:
def times(l: List[Char]) = l.groupBy(c => c).mapValues(_.size).toList
times(List('a','b','a')) // outputs List[(Char, Int)] = List((b,1), (a,2))
.groupBy(c => c) gives you Map[Char,List[Char]] = Map(b -> List(b), a -> List(a, a))
Then we use .mapValues(_.size) to map the values of the map to the size of the grouped sub-collections: Map[Char,Int] = Map(b -> 1, a -> 2).
Finally, you convert the map to a list of key-value tuples with .toList to get the final result.
Lastly, if you don't care about the order of the output list as you said, then leaving the output as a Map[Char,Int] conveys better this decision (instead of converting it to a list).

Transform Tuples to Array of Points

Suppose I have a class Point with two properties x and y and k tuples:
val p1 = (1,2)
val p2 = (3,4)
val p3 = (33,3)
val p4 = (6,67)
.
.
val p4 = (3,8)
I want to write a function which I can call like:
val arrayOfPoints = tupleToArray(p1,p2,..,pk)
And it will return Array of Points with
x = first value of the tuple and
y = 2nd value of the tuple.
Note: the number of arguments for the function can be any integer >=1.
If we define Point as a case class, we can turn a (Int, Int) tuple into a Point using Point.tupled.
We can accept a variable number of arguments using the variable arguments notation (Int, Int)*.
A function to turn tuples into Points could look like :
case class Point(x: Int, y: Int)
def tupleToPoints(pairs: (Int, Int)*) =
pairs.map(Point.tupled).toArray
scala> tupleToPoints(p1, p2, p3, p4)
res2: Array[Point] = Array(Point(1,2), Point(3,4), Point(33,3), Point(6,67))
If you have a group of points, you can do :
val points = List(p1, p2, p3, p4)
tupleToPoints(points: _*)
Some extra explanation about Point.tupled:
When you call Point(1, 1), you actually call Point.apply(1, 1). If we check the type of Point.apply, we can see it takes two Ints and returns a Point.
scala> Point.apply _
res21: (Int, Int) => Point = <function2>
In your case we have a tuple (Int, Int) which we would like to turn into a Point. The first idea could be pattern matching :
(1, 1) match { case (x, y) => Point(x, y) }
def tupleToPoints(pairs: (Int, Int)*) =
pairs.map { case (x, y) => Point(x, y) }.toArray
// nicer than map(p => Point(p._1, p._2))
But what if we want to use the tuple directly to create a Point using Point.apply, so we don't need this step ? We can use tupled :
scala> (Point.apply _).tupled
res22: ((Int, Int)) => Point = <function1>
We now have a function which takes a tuple (Int, Int) (instead of two Ints) and returns a Point. Because Point is a case class, we can also use Point.tupled which is exactly the same function :
scala> Point.tupled
res23: ((Int, Int)) => Point = <function1>
We can pass this function in our map :
def tupleToPoints(pairs: (Int, Int)*) =
pairs.map(Point.tupled).toArray
// analogous to map(p => Point.tupled(p))

Applying Multiple Filters on List

Given these two functions:
scala> def maybe(x: Int): Boolean = x % 2 == 0
maybe: (x: Int)Boolean
scala> def good(x: Int): Boolean = x == 10
good: (x: Int)Boolean
Can I apply both good and maybe functions together?
scala> List(10) filter good filter maybe
res104: List[Int] = List(10)
scala> List(10) filter (good && maybe)
<console>:17: error: missing arguments for method good;
follow this method with `_' if you want to treat it as a partially applied function
List(10) filter (good && maybe)
^
You could evaluate them inside an anonymous function:
List(10) filter { x => good(x) && maybe(x) }
You can't really use andThen because composition is like the transitive property.
[(A => Boolean) && (A => Boolean)] != [(A => B) => C]
// ^ What you want ^ Composition
scala> def maybe(x: Int): Boolean = x % 2 == 0
maybe: (x: Int)Boolean
scala> def good(x: Int): Boolean = x % 3 == 0
good: (x: Int)Boolean
scala> (1 to 20) filter { i => List(good _, maybe _).forall(_(i)) }
res1: scala.collection.immutable.IndexedSeq[Int] = Vector(6, 12, 18)

Simple question about tuple of scala

I'm new to scala, and what I'm learning is tuple.
I can define a tuple as following, and get the items:
val tuple = ("Mike", 40, "New York")
println("Name: " + tuple._1)
println("Age: " + tuple._2)
println("City: " + tuple._3)
My question is:
How to get the length of a tuple?
Is tuple mutable? Can I modify its items?
Is there any other useful operation we can do on a tuple?
Thanks in advance!
1] tuple.productArity
2] No.
3] Some interesting operations you can perform on tuples: (a short REPL session)
scala> val x = (3, "hello")
x: (Int, java.lang.String) = (3,hello)
scala> x.swap
res0: (java.lang.String, Int) = (hello,3)
scala> x.toString
res1: java.lang.String = (3,hello)
scala> val y = (3, "hello")
y: (Int, java.lang.String) = (3,hello)
scala> x == y
res2: Boolean = true
scala> x.productPrefix
res3: java.lang.String = Tuple2
scala> val xi = x.productIterator
xi: Iterator[Any] = non-empty iterator
scala> while(xi.hasNext) println(xi.next)
3
hello
See scaladocs of Tuple2, Tuple3 etc for more.
One thing that you can also do with a tuple is to extract the content using the match expression:
def tupleview( tup: Any ){
tup match {
case (a: String, b: String) =>
println("A pair of strings: "+a + " "+ b)
case (a: Int, b: Int, c: Int) =>
println("A triplet of ints: "+a + " "+ b + " " +c)
case _ => println("Unknown")
}
}
tupleview( ("Hello", "Freewind"))
tupleview( (1,2,3))
Gives:
A pair of strings: Hello Freewind
A triplet of ints: 1 2 3
Tuples are immutable, but, like all cases classes, they have a copy method that can be used to create a new Tuple with a few changed elements:
scala> (1, false, "two")
res0: (Int, Boolean, java.lang.String) = (1,false,two)
scala> res0.copy(_2 = true)
res1: (Int, Boolean, java.lang.String) = (1,true,two)
scala> res1.copy(_1 = 1f)
res2: (Float, Boolean, java.lang.String) = (1.0,true,two)
Concerning question 3:
A useful thing you can do with Tuples is to store parameter lists for functions:
def f(i:Int, s:String, c:Char) = s * i + c
List((3, "cha", '!'), (2, "bora", '.')).foreach(t => println((f _).tupled(t)))
//--> chachacha!
//--> borabora.
[Edit] As Randall remarks, you'd better use something like this in "real life":
def f(i:Int, s:String, c:Char) = s * i + c
val g = (f _).tupled
List((3, "cha", '!'), (2, "bora", '.')).foreach(t => println(g(t)))
In order to extract the values from tuples in the middle of a "collection transformation chain" you can write:
val words = List((3, "cha"),(2, "bora")).map{ case(i,s) => s * i }
Note the curly braces around the case, parentheses won't work.
Another nice trick ad question 3) (as 1 and 2 are already answered by others)
val tuple = ("Mike", 40, "New York")
tuple match {
case (name, age, city) =>{
println("Name: " + name)
println("Age: " + age)
println("City: " + city)
}
}
Edit: in fact it's rather a feature of pattern matching and case classes, a tuple is just a simple example of a case class...
You know the size of a tuple, it's part of it's type. For example if you define a function def f(tup: (Int, Int)), you know the length of tup is 2 because values of type (Int, Int) (aka Tuple2[Int, Int]) always have a length of 2.
No.
Not really. Tuples are useful for storing a fixed amount of items of possibly different types and passing them around, putting them into data structures etc. There's really not much you can do with them, other than creating tuples, and getting stuff out of tuples.
1 and 2 have already been answered.
A very useful thing that you can use tuples for is to return more than one value from a method or function. Simple example:
// Get the min and max of two integers
def minmax(a: Int, b: Int): (Int, Int) = if (a < b) (a, b) else (b, a)
// Call it and assign the result to two variables like this:
val (x, y) = minmax(10, 3) // x = 3, y = 10
Using shapeless, you easily get a lot of useful methods, that are usually available only on collections:
import shapeless.syntax.std.tuple._
val t = ("a", 2, true, 0.0)
val first = t(0)
val second = t(1)
// etc
val head = t.head
val tail = t.tail
val init = t.init
val last = t.last
val v = (2.0, 3L)
val concat = t ++ v
val append = t :+ 2L
val prepend = 1.0 +: t
val take2 = t take 2
val drop3 = t drop 3
val reverse = t.reverse
val zip = t zip (2.0, 2, "a", false)
val (unzip, other) = zip.unzip
val list = t.toList
val array = t.toArray
val set = t.to[Set]
Everything is typed as one would expect (that is first has type String, concat has type (String, Int, Boolean, Double, Double, Long), etc.)
The last method above (.to[Collection]) should be available in the next release (as of 2014/07/19).
You can also "update" a tuple
val a = t.updatedAt(1, 3) // gives ("a", 3, true, 0.0)
but that will return a new tuple instead of mutating the original one.