Scala: map(f) and map(_.f) - scala

I thought in scala map(f) is the same as map(_.f) as map(x => x.f), but turns out it is not
scala> val a = List(1,2,3)
val a: List[Int] = List(1, 2, 3)
scala> a.map(toString)
val res7: List[Char] = List(l, i, n)
scala> a.map(_.toString)
val res8: List[String] = List(1, 2, 3)
What happenes when a.map(toString) is called? Where did the three charaacters l, i, and n come from?

map(f) is not the same as map(_.f()). It's the same as map(f(_)). That is, it's going to call f(x), not x.f(), for each x in the list.
So a.map(toString) should be an error because the normal toString method does not take any arguments. My guess is that in your REPL session you've defined your own toString method that takes an argument and that's the one that's being called.

Related

Scala: Convert heterogeneous Tuple to List

On the Scala command line, there is no problem writing:
List((1,2),(1,'a'))
But I can't seem to write a function that would convert a Tuple2 to a List, because Tuple2 takes 2 type parameters, but List only one. Any attempt such as:
def tuple2ToList[T1, T2](pair: (T1, T2)): List[Any] = List(pair._1, pair._2)
seems to be bound to lose type information. Is there anything we can do to preserve some type information in the process?
This is a solution proposed by #BenReich in a comment
Simply use one type parameter instead of two, the compiler will
automatically select the least upper bound of the types of the two
tuple elements:
def tupleToList[T](p: (T, T)): List[T] = List(p._1, p._2)
Examples:
scala> tupleToList((Some(42), None))
res4: List[Option[Int]] = List(Some(42), None)
scala> tupleToList((0.9999, 1))
res5: List[AnyVal] = List(0.9999, 1)
scala> tupleToList((Set(1), List(1)))
res6: List[scala.collection.immutable.Iterable[Int] with Int => AnyVal] = List(Set(1), List(1))
This is the old suboptimal solution, I'll leave it here as context for #BenReich's comment.
Define the return type as the least upper bound of T1 and T2:
def tupleToListRescueTypeInfo[R, T1 <: R, T2 <: R](p: (T1, T2)): List[R] =
List(p._1, p._2)
Little test:
scala> tupleToListRescueTypeInfo((2, 3))
res0: List[Int] = List(2, 3)
scala> tupleToListRescueTypeInfo((Some[Int](3), None))
res1: List[Option[Int]] = List(Some(3), None)
scala> tupleToListRescueTypeInfo((List(1,2), Set(1,2)))
res2: List[scala.collection.immutable.Iterable[Int] with Int => AnyVal] =
List(List(1, 2), Set(1, 2))
It obviously cannot preserve all type information, but it at least attempts to rescue as much as possible.

Ommiting parenthesis in adding elements to List

I'm trying to add element to a List[String] while omitting annoying parenthesis. I tried this:
object Main extends App {
val l = List("fds")
val xs1: List[String] = l.+:("123") // ok
val xs2: List[String] = l +: "123" // compile-error
}
DEMO
Why is omitting parenthesis causing compile-error? These assignments look the same to me. What is the difference?
It's happening because of right associative methods.
scala> val l = List("abc")
l: List[String] = List(abc)
scala> "efg" +: l
res3: List[String] = List(efg, abc)
Read more here What good are right-associative methods in Scala?
Error case
scala> val l = List(1, 2, 3)
l: List[Int] = List(1, 2, 3)
scala> 4 +: l
res1: List[Int] = List(4, 1, 2, 3)
scala> l +: 1
<console>:13: error: value +: is not a member of Int
l +: 1
^
Because +: is right associative. Method +: is getting invoked on Int instead of list
In order to make it work we can explicitly invoke method on list without the special operator syntax
scala> val l = List(1, 2, 3)
l: List[Int] = List(1, 2, 3)
scala> l.+:(1)
res4: List[Int] = List(1, 1, 2, 3)
Above case works because its normal method invocation.

How to avoid calling toVector on each Scala for comprehension / yield?

I have several methods that operate on Vector sequences and the following idiom is common when combining data from multiple vectors into a single one with the use of a for comprehension / yield:
(for (i <- 0 until y.length) yield y(i) + 0.5*dy1(i)) toVector
Notice the closing toVector and the enclosing parentheses around the for comprehension. I want to get rid of it because it's ugly, but removing it produces the following error:
type mismatch;
found : scala.collection.immutable.IndexedSeq[Double]
required: Vector[Double]
Is there a better way of achieving what I want that avoids explicitly calling toVector many times to essentially achieve a non-operation (converting and indexed sequence...to an indexed sequence)?
One way to avoid collection casting, e.g. toVector, is to invoke, if possible, only those methods that return the same collection type.
y.zipWithIndex.map{case (yv,idx) => yv + 0.5*dy1(idx)}
for yield on Range which you are using in your example yields a Vector[T] by default.
example,
scala> val squares= for (x <- Range(1, 3)) yield x * x
squares: scala.collection.immutable.IndexedSeq[Int] = Vector(1, 4)
check the type,
scala> squares.isInstanceOf[Vector[Int]]
res14: Boolean = true
Note that Vector[T] also extends IndexedSeq[T].
#SerialVersionUID(-1334388273712300479L)
final class Vector[+A] private[immutable] (private[collection] val startIndex: Int, private[collection] val endIndex: Int, focus: Int)
extends AbstractSeq[A]
with IndexedSeq[A]
with GenericTraversableTemplate[A, Vector]
with IndexedSeqLike[A, Vector[A]]
with VectorPointer[A #uncheckedVariance]
with Serializable
with CustomParallelizable[A, ParVector[A]]
That's why above result is also an instance of IndexedSeq[T],
scala> squares.isInstanceOf[IndexedSeq[Int]]
res15: Boolean = true
You can define the type of your result as IndexedSeq[T] and still achieve what you want with Vector without explicitly calling .toVector
scala> val squares: IndexedSeq[Int] = for (x <- Range(1, 3)) yield x * x
squares: IndexedSeq[Int] = Vector(1, 4)
scala> squares == Vector(1, 4)
res16: Boolean = true
But for yield on Seq[T] gives List[T] by default.
scala> val squares = for (x <- Seq(1, 3)) yield x * x
squares: Seq[Int] = List(1, 9)
Only in that case if you want vector you must .toVector the result.
scala> squares.isInstanceOf[Vector[Int]]
res21: Boolean = false
scala> val squares = (for (x <- Seq(1, 3)) yield x * x).toVector
squares: Vector[Int] = Vector(1, 9)

Prepend to an Iterable?

How can I prepend, i.e. cons, to an Iterable?
scala> val xs: Iterable[Int] = Seq(1)
xs: Iterable[Int] = List(1)
scala> xs :: 5
<console>:15: error: value :: is not a member of Int
xs :: 5
^
I looked at the docs, but didn't figure it out.
:: is specific to List. It is a List, in fact.
There is no concept of prepending to an Iterable, as not all Iterables will guarantee order (Set does not, for example). You may want Seq instead, which would use +: to prepend.
Iterable doesn't have a prepend method, but you can use "++" to join two iterables:
scala> val xs: Iterable[Int] = Seq(1)
xs: Iterable[Int] = List(1)
scala> List(5) ++ xs
res0: List[Int] = List(5, 1)
Seq does have a prepend method, +:, and you could convert to a seq:
scala> 5 +: xs.toSeq
res1: Seq[Int] = List(5, 1)

Scala Iteratively build lists

As a Scala beginner I am still struggling working with immutable lists. All I am trying to do append elements to my list. Here's an example of what I am trying to do.
val list = Seq()::Nil
val listOfInts = List(1,2,3)
listOfInts.foreach {case x=>
list::List(x)
}
expecting that I would end up with a list of lists: List(List(1),List(2),List(3))
Coming from java I am used to just using list.add(new ArrayList(i)) to get the same result. Am I way off here?
Since the List is immutable you can not modify the List in place.
To construct a List of 1 item Lists from a List, you can map over the List. The difference between forEach and map is that forEach returns nothing, i.e. Unit, while map returns a List from the returns of some function.
scala> def makeSingleList(j:Int):List[Int] = List(j)
makeSingleList: (j: Int)List[Int]
scala> listOfInts.map(makeSingleList)
res1: List[List[Int]] = List(List(1), List(2), List(3))
Below is copy and pasted from the Scala REPL with added print statement to see what is happening:
scala> val list = Seq()::Nil
list: List[Seq[Nothing]] = List(List())
scala> val listOfInts = List(1,2,3)
listOfInts: List[Int] = List(1, 2, 3)
scala> listOfInts.foreach { case x=>
| println(list::List(x))
| }
List(List(List()), 1)
List(List(List()), 2)
List(List(List()), 3)
During the first iteration of the foreach loop, you are actually taking the first element of listOfInts (which is 1), putting that in a new list (which is List(1)), and then adding the new element list (which is List(List()) ) to the beginning of List(1). This is why it prints out List(List(List()), 1).
Since your list and listOfInts are both immutable, you can't change them. All you can do is perform something on them, and then return a new list with the change. In your case list::List(x) inside the loop actually doesnt do anything you can see unless you print it out.
There are tutorials on the documentation page.
There is a blurb for ListBuffer, if you swing that way.
Otherwise,
scala> var xs = List.empty[List[Int]]
xs: List[List[Int]] = List()
scala> (1 to 10) foreach (i => xs = xs :+ List(i))
scala> xs
res9: List[List[Int]] = List(List(1), List(2), List(3), List(4), List(5), List(6), List(7), List(8), List(9), List(10))
You have a choice of using a mutable builder like ListBuffer or a local var and returning the collection you build.
In the functional world, you often build by prepending and then reverse:
scala> var xs = List.empty[List[Int]]
xs: List[List[Int]] = List()
scala> (1 to 10) foreach (i => xs = List(i) :: xs)
scala> xs.reverse
res11: List[List[Int]] = List(List(1), List(2), List(3), List(4), List(5), List(6), List(7), List(8), List(9), List(10))
Given val listOfInts = List(1,2,3), and you want the final result as List(List(1),List(2),List(3)).
Another nice trick I can think of is sliding(Groups elements in fixed size blocks by passing a "sliding window" over them)
scala> val listOfInts = List(1,2,3)
listOfInts: List[Int] = List(1, 2, 3)
scala> listOfInts.sliding(1)
res6: Iterator[List[Int]] = non-empty iterator
scala> listOfInts.sliding(1).toList
res7: List[List[Int]] = List(List(1), List(2), List(3))
// If pass 2 in sliding, it will be like
scala> listOfInts.sliding(2).toList
res8: List[List[Int]] = List(List(1, 2), List(2, 3))
For more about the sliding, you can have a read about sliding in scala.collection.IterableLike.
You can simply map over this list to create a List of Lists.
It maintains Immutability and functional approach.
scala> List(1,2,3).map(List(_))
res0: List[List[Int]] = List(List(1), List(2), List(3))
Or you, can also use Tail Recursion :
#annotation.tailrec
def f(l:List[Int],res:List[List[Int]]=Nil) :List[List[Int]] = {
if(l.isEmpty) res else f(l.tail,res :+ List(l.head))
}
scala> f(List(1,2,3))
res1: List[List[Int]] = List(List(1), List(2), List(3))
In scala you have two (three, as #som-snytt has shown) options -- opt for a mutable collection (like Buffer):
scala> val xs = collection.mutable.Buffer(1)
// xs: scala.collection.mutable.Buffer[Int] = ArrayBuffer(1)
scala> xs += 2
// res10: xs.type = ArrayBuffer(1, 2)
scala> xs += 3
// res11: xs.type = ArrayBuffer(1, 2, 3)
As you can see, it works just like you would work with lists in Java. The other option you have, and in fact it's highly encouraged, is to opt to processing list functionally, that's it, you take some function and apply it to each and every element of collection:
scala> val ys = List(1,2,3,4).map(x => x + 1)
// ys: List[Int] = List(2, 3, 4, 5)
scala> def isEven(x: Int) = x % 2 == 0
// isEven: (x: Int)Boolean
scala> val zs = List(1,2,3,4).map(x => x * 10).filter(isEven)
// zs: List[Int] = List(10, 20, 30, 40)
// input: List(1,2,3)
// expected output: List(List(1), List(2), List(3))
val myList: List[Int] = List(1,2,3)
val currentResult = List()
def buildIteratively(input: List[Int], currentOutput: List[List[Int]]): List[List[Int]] = input match {
case Nil => currentOutput
case x::xs => buildIteratively(xs, List(x) :: currentOutput)
}
val result = buildIteratively(myList, currentResult).reverse
You say in your question that the list is immutable, so you do are aware that you cannot mutate it ! All operations on Scala lists return a new list. By the way, even in Java using a foreach to populate a collection is considered a bad practice. The Scala idiom for your use-case is :
list ::: listOfInts
Shorter, clearer, more functional, more idiomatic and easier to reason about (mutability make things more "complicated" especially when writing lambda expressions because it breaks the semantic of a pure function). There is no good reason to give you a different answer.
If you want mutability, probably for performance purposes, use a mutable collection such as ArrayBuffer.