Scala: On strange behavior of `foldLeft` - scala

Define:
val a = List(1, 2, 3, 4, 5, 6, 7)
Consider the following line with foldLeft:
a.foldLeft(""){case (num, sum) => sum + (num.toString + "-")}
My expectation was that the program is going to do:
((((( "7-" + "6-" ) + "5-" ) + "4-" ) + "3-" ) + "2-" ) + "1-"
which is 7-6-5-4-3-2-1-
But what I get is: 7654321-------. Why is this the case?

You mixed up the parameters to foldLeft. Check the documentation for List.foldLeft. Note that the z "zero" value has the same type as the second parameter in the function argument, not the first.
This should work closer to expected:
a.foldLeft(""){case (sum, num) => sum + (num.toString + "-")}
// res0: String = 1-2-3-4-5-6-7-
However, if you want the numbers in reverse-order, then you might want to use foldRight. Maybe this is actually what you were going for in the first place (notice that the arguments num and sum are in the same order you gave):
a.foldRight(""){case (num, sum) => sum + (num.toString + "-")}
// res1: String = 7-6-5-4-3-2-1-

From your expectation, I expect you expected foldRight behavior:
scala> val a = List(1, 2, 3, 4, 5, 6, 7)
a: List[Int] = List(1, 2, 3, 4, 5, 6, 7)
scala> a.foldRight(""){case (num, sum) => sum + (num.toString + "-")}
res0: String = 7-6-5-4-3-2-1-

Related

if condition for partial argument in map

I understand how to use if in map. For example, val result = list.map(x => if (x % 2 == 0) x * 2 else x / 2).
However, I want to use if for only part of the arguments.
val inputColumns = List(
List(1, 2, 3, 4, 5, 6), // first "column"
List(4, 6, 5, 7, 12, 15) // second "column"
)
inputColumns.zipWithIndex.map{ case (col, idx) => if (idx == 0) col * 2 else col / 10}
<console>:1: error: ';' expected but integer literal found.
inputColumns.zipWithIndex
res4: List[(List[Int], Int)] = List((List(1, 2, 3, 4, 5, 6),0), (List(4, 6, 5, 7, 12, 15),1))
I have searched the error info but have not found a solution.
Why my code is not 'legal' in Scala? Is there a better way to write it? Basically, I want to do a pattern matching and then do something on other arguments.
To explain your problem another way, inputColumns has type List[List[Int]]. You can verify this in the Scala REPL:
$ scala
Welcome to Scala 2.12.4 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_161).
Type in expressions for evaluation. Or try :help.
scala> val inputColumns = List(
| List(1, 2, 3, 4, 5, 6), // first "column"
| List(4, 6, 5, 7, 12, 15) // second "column"
| )
inputColumns: List[List[Int]] = List(List(1, 2, 3, 4, 5, 6), List(4, 6, 5, 7, 12, 15))
Now, when you call .zipWithIndex on that list, you end up with a List[(List[Int], Int)] - that is, a list of a tuple, in which the first tuple type is a List[Int] (the column) and the second is an Int (the index):
scala> inputColumns.zipWithIndex
res0: List[(List[Int], Int)] = List((List(1, 2, 3, 4, 5, 6),0), (List(4, 6, 5, 7, 12, 15),1))
Consequently, when you try to apply a map function to this list, col is a List[Int] and not an Int, and so col * 2 makes no sense - you're multiplying a List[Int] by 2. You then also try to divide the list by 10, obviously.
scala> inputColumns.zipWithIndex.map{ case(col, idx) => if(idx == 0) col * 2 else col / 10 }
<console>:13: error: value * is not a member of List[Int]
inputColumns.zipWithIndex.map{ case(col, idx) => if(idx == 0) col * 2 else col / 10 }
^
<console>:13: error: value / is not a member of List[Int]
inputColumns.zipWithIndex.map{ case(col, idx) => if(idx == 0) col * 2 else col / 10 }
^
In order to resolve this, it depends what you're trying to achieve. If you want a single list of integers, and then zip those so that each value has an associated index, you should call flatten on inputColumns before calling zipWithIndex. This will result in List[(Int, Int)], where the first value in the tuple is the column value, and the second is the index. Your map function will then work correctly without modification:
scala> inputColumns.flatten.zipWithIndex.map{ case(col, idx) => if(idx == 0) col * 2 else col / 10 }
res3: List[Int] = List(2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1)
Of course, you no longer have separate columns.
If you wish each value in each list to have an associated index, you need to firstly map inputColumns into two zipped lists, using inputColumns.map(_.zipWithIndex) to create a List[List[(Int, Int)]] - a list of a list of (Int, Int) tuples:
scala> inputColumns.map(_.zipWithIndex)
res4: List[List[(Int, Int)]] = List(List((1,0), (2,1), (3,2), (4,3), (5,4), (6,5)), List((4,0), (6,1), (5,2), (7,3), (12,4), (15,5)))
We can now apply your original map function to the result of the zipWithIndex operation:
scala> inputColumns.map(_.zipWithIndex.map { case (col, idx) => if(idx == 0) col * 2 else col / 10 })
res5: List[List[Int]] = List(List(2, 0, 0, 0, 0, 0), List(8, 0, 0, 0, 1, 1))
The result is another List[List[Int]] with each internal list being the results of your map operation on the original two input columns.
On the other hand, if idx is meant to be the index of the column, and not of each value, and you want to multiply all of the values in the first column by 2 and divide all of the values in the other columns by 10, then you need to change your original map function to map across each column, as follows:
scala> inputColumns.zipWithIndex.map {
| case (col, idx) => {
| if(idx == 0) col.map(_ * 2) // Multiply values in first column by 1
| else col.map(_ / 10) // Divide values in all other columns by 10
| }
| }
res5: List[List[Int]] = List(List(2, 4, 6, 8, 10, 12), List(0, 0, 0, 0, 1, 1))
Let me know if you require any further clarification...
UPDATE:
The use of case in map is a common Scala shorthand. If a higher-order function takes a single argument, something such as this:
def someHOF[A, B](x: A => B) = //...
and you call that function like this (with what Scala terms a partial function - a function consisting solely of a list of case statements):
someHOF {
case expr1 => //...
case expr2 => //...
...
}
then Scala treats it as a kind-of shorthand for:
someHOF {a =>
a match {
case expr1 => //...
case expr2 => //...
...
}
}
or, being slightly more terse,
someHOF {
_ match {
case expr1 => //...
case expr2 => //...
...
}
}
For a List, for example, you can use it with functions such as map, flatMap, filter, etc.
In the case of your map function, the sole argument is a tuple, and the sole case statement acts to break open the tuple and expose its contents. That is:
val l = List((1, 2), (3, 4), (5, 6))
l.map { case(a, b) => println(s"First is $a, second is $b") }
is equivalent to:
l.map {x =>
x match {
case (a, b) => println(s"First is $a, second is $b")
}
}
and both will output:
First is 1, second is 2
First is 3, second is 4
First is 5, second is 6
Note: This latter is a bit of a dumb example, since map is supposed to map (i.e. change) the values in the list into new values in a new list. If all you were doing was printing the values, this would be better:
val l = List((1, 2), (3, 4), (5, 6))
l.foreach { case(a, b) => println(s"First is $a, second is $b") }
You are trying to multiply a list by 2 when you do col * 2 as col is List(1, 2, 3, 4, 5, 6) when idx is 0, which is not possible and similar is the case with else part col / 10
If you are trying to multiply the elements of first list by 2 and devide the elements of rest of the list by 10 then you should be doing the following
inputColumns.zipWithIndex.map{ case (col, idx) => if (idx == 0) col.map(_*2) else col.map(_/10)}
Even better approach would be to use match case
inputColumns.zipWithIndex.map(x => x._2 match {
case 0 => x._1.map(_*2)
case _ => x._1.map(_/10)
})

Map add element and return two instead of 1

Imagine that I have the following List l. Is it possible by using map to return a list similar to the result below but if let's say the number is 2 to return the result twice? e.g.
l.map( x => if (x=2) (return twice) x*2 )
so the resulted list should be
List(2, 4, 4, 6, 8, 10)
instead of the one presented below.
scala> val l = List(1,2,3,4,5)
scala> l.map( x => x*2 )
res60: List[Int] = List(2, 4, 6, 8, 10)
You are looking for .flatMap
l.flatMap {
case 2 => Seq(4,4)
case x => Seq(x*2)
}

How to take the first distinct (until the moment) elements of a list?

I am sure there is an elegant/funny way of doing it,
but I can only think of a more or less complicated recursive solution.
Rephrasing:
Is there any standard lib (collections) method nor simple combination of them to take the first distinct elements of a list?
scala> val s = Seq(3, 5, 4, 1, 5, 7, 1, 2)
s: Seq[Int] = List(3, 5, 4, 1, 5, 7, 1, 2)
scala> s.takeWhileDistinct //Would return Seq(3,5,4,1), it should preserve the original order and ignore posterior occurrences of distinct values like 7 and 2.
If you want it to be fast-ish, then
{ val hs = scala.collection.mutable.HashSet[Int]()
s.takeWhile{ hs.add } }
will do the trick. (Extra braces prevent leaking the temp value hs.)
This is a short approach in a maximum of O(2logN).
implicit class ListOps[T](val s: Seq[T]) {
def takeWhileDistinct: Seq[T] = {
s.indexWhere(x => { s.count(x==) > 1 }) match {
case ind if (ind > 0) => s.take(
s.indexWhere(x => { s.count(x==) > 1 }, ind + 1) + ind).distinct
case _ => s
}
}
}
val ex = Seq(3, 5, 4, 5, 7, 1)
val ex2 = Seq(3, 5, 4, 1, 5, 7, 1, 5)
println(ex.takeWhileDistinct.mkString(", ")) // 3, 4, 5
println(ex2.takeWhileDistinct.mkString(", ")) // 3, 4, 5, 1
Look here for live results.
Interesting problem. Here's an alternative. First, let's get the stream of s so we can avoid unnecessary work (though the overhead is likely to be greater than the saved work, sadly).
val s = Seq(3, 5, 4, 5, 7, 1)
val ss = s.toStream
Now we can build s again, but keeping track of whether there are repetitions or not, and stopping at the first one:
val newS = ss.scanLeft(Seq[Int]() -> false) {
case ((seen, stop), current) =>
if (stop || (seen contains current)) (seen, true)
else ((seen :+ current, false))
}
Now all that's left is take the last element without repetition, and drop the flag:
val noRepetitionsS = newS.takeWhile(!_._2).last._1
A variation on Rex's (though I prefer his...)
This one is functional throughout, using the little-seen scanLeft method.
val prevs = xs.scanLeft(Set.empty[Int])(_ + _)
(xs zip prevs) takeWhile { case (x,prev) => !prev(x) } map {_._1}
UPDATE
And a lazy version (using iterators, for moar efficiency):
val prevs = xs.iterator.scanLeft(Set.empty[Int])(_ + _)
(prevs zip xs.iterator) takeWhile { case (prev,x) => !prev(x) } map {_._2}
Turn the resulting iterator back to a sequence if you want, but this'll also work nicely with iterators on both the input AND the output.
The problem is simpler than the std lib function I was looking for (takeWhileConditionOverListOfAllAlreadyTraversedItems):
scala> val s = Seq(3, 5, 4, 1, 5, 7, 1, 2)
scala> s.zip(s.distinct).takeWhile{case(a,b)=>a==b}.map(_._1)
res20: Seq[Int] = List(3, 5, 4, 1)

Stream of running sums in Scala

This is a follow-up to my previous question.
Given function add_stream(s1:Stream[Int], s2:Stream[Int]):Stream[Int]
I would like to code running_sums(s:Stream[Int]):Stream[Int], which returns a new stream : s1, s1 + s2, s1 + s2 + s3, ...
I can think of the following implementation but it does not work if s is empty
def running_sums(s:Stream[Int]):Stream[Int] =
Stream.cons(s.head, add_streams(s.tail, running_sums(s)))
I can fix it as follows:
def running_sums(s:Stream[Int]):Stream[Int] =
if (s.isEmpty) empty
else Stream.cons(s.head, add_streams(s.tail, running_sums(s)))
However it does not look elegant.
How would you implement running_sums?
There's a library call for something like this, called scanLeft
s.scanLeft(0)(_+_).tail
What about scanLeft?
scala> val sums = stream.scanLeft(List(0))((ns, n) => ns :+ (ns.last + n))
sums: scala.collection.immutable.Stream[List[Int]] = Stream(List(0), ?)
scala> sums take 5 foreach println
List(0)
List(0, 1)
List(0, 1, 3)
List(0, 1, 3, 6)
List(0, 1, 3, 6, 10)

Replace element in List with scala

How do you replace an element by index with an immutable List.
E.g.
val list = 1 :: 2 ::3 :: 4 :: List()
list.replace(2, 5)
If you want to replace index 2, then
list.updated(2,5) // Gives 1 :: 2 :: 5 :: 4 :: Nil
If you want to find every place where there's a 2 and put a 5 in instead,
list.map { case 2 => 5; case x => x } // 1 :: 5 :: 3 :: 4 :: Nil
In both cases, you're not really "replacing", you're returning a new list that has a different element(s) at that (those) position(s).
In addition to what has been said before, you can use patch function that replaces sub-sequences of a sequence:
scala> val list = List(1, 2, 3, 4)
list: List[Int] = List(1, 2, 3, 4)
scala> list.patch(2, Seq(5), 1) // replaces one element of the initial sequence
res0: List[Int] = List(1, 2, 5, 4)
scala> list.patch(2, Seq(5), 2) // replaces two elements of the initial sequence
res1: List[Int] = List(1, 2, 5)
scala> list.patch(2, Seq(5), 0) // adds a new element
res2: List[Int] = List(1, 2, 5, 3, 4)
You can use list.updated(2,5) (which is a method on Seq).
It's probably better to use a scala.collection.immutable.Vector for this purpose, becuase updates on Vector take (I think) constant time.
You can use map to generate a new list , like this :
# list
res20: List[Int] = List(1, 2, 3, 4, 4, 5, 4)
# list.map(e => if(e==4) 0 else e)
res21: List[Int] = List(1, 2, 3, 0, 0, 5, 0)
It can also be achieved using patch function as
scala> var l = List(11,20,24,31,35)
l: List[Int] = List(11, 20, 24, 31, 35)
scala> l.patch(2,List(27),1)
res35: List[Int] = List(11, 20, 27, 31, 35)
where 2 is the position where we are looking to add the value, List(27) is the value we are adding to the list and 1 is the number of elements to be replaced from the original list.
If you do a lot of such replacements, it is better to use a muttable class or Array.
following is a simple example of String replacement in scala List, you can do similar for other types of data
scala> val original: List[String] = List("a","b")
original: List[String] = List(a, b)
scala> val replace = original.map(x => if(x.equals("a")) "c" else x)
replace: List[String] = List(c, b)