List type mismatch when appending in Scala - scala

Let's say I have following code:
val xs: List[Int] = List(1, 2, 3)
val ys: List[Int] = List(4, 5, 6)
val zs: List[Int] = xs.appended(ys)
The last line does not compile with an error:
Error:(162, 33) type mismatch; found : List[Int] required: Int val
zs: List[Int] = xs.appended(ys)
If I remove the explicit type declaration, then the code compiles, but the real problem is that
the error message appears in a recursive function where I would like to pass appended list as a parameter of type List[Int], so removing the explicit type is not an option.

According to scaladoc appended method takes only one argument, not an entire list. So the following examples will compile:
xs.appended(ys(0))
for(x <- xs) yield ys appended x
or appendAll:
xs appendAll ys
ys :++ xs
P.S.: Note, that appending to the list is not optimal, as it's time is proportional to the size of the list, prefer prepend instead:
ys ::: xs

According scala documentation appended method accepting just one element, not collection. And zs type after removing explicit types will be List[Any]:
val xs = List(1, 2, 3)
val ys = List(4, 5, 6)
val zs: List[Any] = xs.appended(ys) // List(1, 2, 3, List(4, 5, 6))
it compiles, but result will be List(1, 2, 3, List(4, 5, 6))
You can use method appendedAll to do that you want or just concatenate lists using concat or ++ operator :
val xs = List(1, 2, 3)
val ys = List(4, 5, 6)
val zs: List[Int] = xs ++ ys // List(1, 2, 3, 4, 5, 6)
val as: List[Int] = xs.appendedAll(ys) // List(1, 2, 3, 4, 5, 6)
val bs: List[Int] = xs.concat(ys) // List(1, 2, 3, 4, 5, 6)

1. val xs: List[Int] = List(1, 2, 3)
2. val ys: List[Int] = List(4, 5, 6)
3. val zs: List[Int] = xs.appended(ys)
The third line is a problem until you have the type declaration. Because when you compile your code compiler is not going to infer the type of the variable zs and it will expect the output of xs.appended(ys) to be a List[Int] which is not the case because xs is List[Int] now if you want to add an element in this list you can do xs.append(1) or any other integer but you are trying to insert List[Int] which is not Int.
Now when you remove the type declaration from line 3 it compile successfully because now compiler will infer the type of the variable zs and if you will see on REPL it will say the of this variable zs is List[Any].
Now if you want to add list into a list and get a flatten result you can simply use
val zs: List[Int] = xs ::: ys
If you will see the scala docs here
this is the signature of appended:
final def:+[B >: A](elem: B): List[B]
:+ is Alias for appended
:++ is Alias for appendedAll
As we can see from the signature appended function takes a parameter of type B and return List[B] in your case B is Int and you are trying to add List[Int].
I hope it clears why you are getting the compilation error.

Related

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.

Calling lists concatenation in Scala

Can someone explain what is going on with
scala> List(1,2).:::(List(3,4))
res15: List[Int] = List(3, 4, 1, 2)
scala> List(1,2) ::: List(3,4)
res16: List[Int] = List(1, 2, 3, 4)
How can the method call results differ while they should be the same method call?
In case of List(1,2).:::(List(3,4)) you call ::: method directly on object List(1,2). According to the docs:
#param prefix The list elements to prepend.
So you get: res15: List[Int] = List(3, 4, 1, 2)
When you do not use . (dot) notation ::: behaves as right associative operation according to the docs:
#usecase def :::(prefix: List[A]): List[A]
#inheritdoc
Example:
{{{List(1, 2) ::: List(3, 4) = List(3, 4).:::(List(1, 2)) = List(1, 2, 3, 4)}}}
That means that in the case of List(1,2) ::: List(3,4) method ::: is being called on object List(3,4).
Right associative operation means basically the following:
xs ::: ys ::: zs is interpreted as xs ::: (ys ::: zs)
Section 16.6 describes the same as example.

Why different behaviors for list concatenation?

What is the difference between a ::: b and a.:::(b) ?
scala> val a = List(1,2,3,4)
a: List[Int] = List(1, 2, 3, 4)
scala> val b = List(5)
b: List[Int] = List(5)
scala> a.:::(b)
res6: List[Int] = List(5, 1, 2, 3, 4)
scala> a ::: b
res7: List[Int] = List(1, 2, 3, 4, 5)
All functions in Scala which end with a : are right-associative and, thus, the expression a ::: b evaluates to b.:::(a).
When you use infix notation, methods (or operators) that end with : are right associative - in other words, the method is called on the object to its right, and the object to its left is passed as an argument.
So 1 :: Nil is the same as Nil.::(1). Just as a ::: b is the same as b.:::(a).
Because when you type
a ::: b
the last ':' makes the function right associative.
Thus, you are calling ::: on b not a:
b.:::(a)

What is Scalas Product.productIterator supposed to do?

Can someone tell me why I am getting different results when using Tuple2[List,List] and List[List] as my Product in the code below? Specifically I would like to know why the second value of the list of lists gets wrapped in another list?
scala> val a = List(1,2,3)
a: List[Int] = List(1, 2, 3)
scala> val b = List(4,5,6)
b: List[Int] = List(4, 5, 6)
scala> val c = List(a,b)
c: List[List[Int]] = List(List(1, 2, 3), List(4, 5, 6))
scala> c.productIterator.foreach( println(_) )
List(1, 2, 3)
List(List(4, 5, 6)) // <-- Note this
scala> val d = (a,b)
d: (List[Int], List[Int]) = (List(1, 2, 3),List(4, 5, 6))
scala> d.productIterator.foreach( println(_) )
List(1, 2, 3)
List(4, 5, 6) // <-- Compared to this
(I have read the (absolutely minimal) description of Scala's Product and the productIterator method on http://www.scala-lang.org/api/current/index.html#scala.Product )
Basically, Tuple means a product between all of its elements, but a non-empty List is a product between its head and tail.
This happens for List, because all case classes extend Product, and represent a product between all their elements similar to tuples. And non-empty List is defined as a case class, containing head and tail: final case class ::[B](override val head: B, private[scala] var tl: List[B]) extends List[B], which inherits the default implementation of Product by case class.
You can observe more of this behaviour with other Lists with 1 or more than 2 elements:
scala> List(a).productIterator.foreach(println)
List(1, 2, 3)
List()
scala> List(a, a).productIterator.foreach(println)
List(1, 2, 3)
List(List(1, 2, 3))
scala> List(a, a, a).productIterator.foreach(println)
List(1, 2, 3)
List(List(1, 2, 3), List(1, 2, 3))

Scala - convert List of Lists into a single List: List[List[A]] to List[A]

What's the best way to convert a List of Lists in scala (2.9)?
I have a list:
List[List[A]]
which I want to convert into
List[A]
How can that be achieved recursively? Or is there any other better way?
List has the flatten method. Why not use it?
List(List(1,2), List(3,4)).flatten
> List(1,2,3,4)
.flatten is obviously the easiest way, but for completeness you should also know about flatMap
val l = List(List(1, 2), List(3, 4))
println(l.flatMap(identity))
and the for-comprehension equivalent
println(for (list <- l; x <- list) yield x)
flatten is obviously a special case of flatMap, which can do so much more.
Given the above example, I'm not sure you need recursion. Looks like you want List.flatten instead.
e.g.
scala> List(1,2,3)
res0: List[Int] = List(1, 2, 3)
scala> List(4,5,6)
res1: List[Int] = List(4, 5, 6)
scala> List(res0,res1)
res2: List[List[Int]] = List(List(1, 2, 3), List(4, 5, 6))
scala> res2.flatten
res3: List[Int] = List(1, 2, 3, 4, 5, 6)
If your structure can be further nested, like:
List(List(1, 2, 3, 4, List(5, 6, List(7, 8))))
This function should give you the desire result:
def f[U](l: List[U]): List[U] = l match {
case Nil => Nil
case (x: List[U]) :: tail => f(x) ::: f(tail)
case x :: tail => x :: f(tail)
}
You don't need recursion but you can use it if you want:
def flatten[A](list: List[List[A]]):List[A] =
if (list.length==0) List[A]()
else list.head ++ flatten(list.tail)
This works like flatten method build into List. Example:
scala> flatten(List(List(1,2), List(3,4)))
res0: List[Int] = List(1, 2, 3, 4)
If you want to use flatmap, here is the the way
Suppose that you have a List of List[Int] named ll, and you want to flat it to List,
many people already gives you the answers, such as flatten, that's the easy way. I assume that you are asking for using flatmap method. If it is the case, here is the way
ll.flatMap(_.map(o=>o))