Scala: Why l1 ::: l2 is not equal with l1.:::(l2)? - list

here is my code:
val l1 = List(1,2,3)
val l2 = List(4,5,6)
val l1l2_1 = l1 ::: l2
val l1l2_2 = l1.:::(l2)
val l1l2_3 = l2.:::(l1)
println(s"l1 = $l1 \nl2 = $l2 \nl1 ::: l2 = $l1l2_1 \nl1.:::(l2) = $l1l2_2 \nl2.:::(l1) = $l1l2_3 }")
and here is output:
l1 = List(1, 2, 3)
l2 = List(4, 5, 6)
l1 ::: l2 = List(1, 2, 3, 4, 5, 6)
l1.:::(l2) = List(4, 5, 6, 1, 2, 3)
l2.:::(l1) = List(1, 2, 3, 4, 5, 6) }
Why l1 ::: l2 is not equal with l1.:::(l2)?

Operators that end in : are treated differently from other ones. When used with infix notation, they reverse their arguments - the method is invoked on the argument on the right and the argument on the left is used as the parameter. So l1 ::: l2 is the same as l2.:::(l1).

Reason is two rules in Scala:
1. : operator/method is right associative.
2. Operator/Methods associativity is determined by the last character in the operator name.
For example:
Any method with arbitrary name, but ending with a :
def myMethod:(a: Any)
is treated like a :, so x myMethod: y is right associative too, and executed like y.myMethod:(x)
Read more in Programming in Scala book: Basic Types and Operations

Related

How to merge two types of for comprehension in Scala?

I have seen for being used different ways in Scala, to take some value out of a wrapper like Option or on list or other collections. If I have to pull a List[Int] out of an Option and then iterate on it, can this be done in one for block?
eg.
val l: Option[List[Int]] = Some(List(1,2,3,4))
l: Option[List[Int]] = Some(List(1, 2, 3, 4))
for{
li <- l // li taken out from Option wrapper
number <- li // numbers pulled from li
} yield number*2
cmd7.scala:3: type mismatch;
found : List[Int]
required: Option[?]
number <- li
^
If I understand correctly it wants each entry to be an Option. Is there some way to achieve this effect without two for loops?
Is there some way to achieve this effect without two for loops?
You can do this by calling toList on the Option[List[Int]], turning it into a List[List[Int]] which the for comprehension will flatMap over:
for {
| o <- l.toList
| num <- o
| } yield num * 2
res8: List[Int] = List(2, 4, 6, 8)
This will yield an empty list for the None type:
scala> val l: Option[List[Int]] = None
scala> for {
| o <- l.toList
| num <- o
| } yield num * 2
res3: List[Int] = List()
You can also use Option[T].getOrElse with an empty List[T] as fallback if the option is empty:
scala> for {
| o <- l.getOrElse(List())
| } yield o * 2
res13: List[Int] = List(2, 4, 6, 8)
Personally, I like the explicit map call:
scala> l.map(_.map(_ * 2))
res7: Option[List[Int]] = Some(List(2, 4, 6, 8))
For comprehensions expand to flatMaps, maps and lazy version of filter. flatMap for Option does not accept function A => List[A]. In general you can use only one type of monad in for comprehension.
Obvious solution here are monad transformers. If you have two monads, one in another, it allows you to access the values inside the deeper monad by creating another monad that combines behavior of two.
Note that this works for any two monads, not just Option and List.
Using scalaz:
import scalaz._
import Scalaz._
val list: Option[List[Int]] = Some(List(1, 2, 3, 4))
(for {
number <- ListT(list)
} yield number * 2).run
res0: Option[List[Int]] = Some(List(2, 4, 6, 8))
You need to call run to unwrap the value from transformer.
you can then use more than one list like this:
val xs = List(1, 2, 3).some
val ys = List(0, 2).some
(for {
x <- ListT(xs)
y <- ListT(ys)
} yield x * y).run
res0: Option[List[Int]] = Some(List(0, 2, 0, 4, 0, 6))
If any Option would be None the result would be None as well
(for {
x <- ListT(xs)
y <- ListT(ys)
z <- ListT(none[List[Int]])
} yield x * y).run
res0: Option[List[Int]] = None

Duplicate list elements which based on predicate

I would like to duplicate even/odd elements in a list.
def even(number: Int): Boolean = {
if(number%2 == 0) true
else false
}
I tried something weird cause i have no idea how should I do that exactly.
scala> var x = List(1, 2, 3)
x: List[Int] = List(1, 2, 3)
scala> x.map(el => if(even(el)) el::x)
res143: List[Any] = List((), List(2, 1, 2, 3), ())
This is not what I expected. I'd like to return only one list with all elements where odd/even are duplicated.
Thanks for your help.
You can use flatMap to return a list per element, either containing just the element itself if the predicate doesn't match, or a list with the element duplicated if it does:
def even(n : Int) : Boolean = n%2 == 0
val l = List(1,2,3)
l.flatMap(n => if(even(n)) List(n,n) else List(n)) // -> List(1, 2, 2, 3)
You can filter the first collection for even numbers, and than concat with the original list:
scala> var l = List(1,2,3)
l: List[Int] = List(1, 2, 3)
scala> l.filter(_ % 2 == 0) ++ l
res14: List[Int] = List(2, 1, 2, 3)
If you want the List[Int] sorted, you can apply that after the concatenation:
scala> l.filter(_ % 2 == 0) ++ l sorted
res15: List[Int] = List(1, 2, 2, 3)
This saves you the allocation of a new List[Int] for every match of even. You filter only the elements you need, creating one List[Int], and then concatenating it with the original.

Scala - select elements from ordered list

I am looking for a nice way to remove first N elements which are equal from the ordered list, e.g.
List(1,1,1,2,3,3)
should return
removeSame(list) -> (1,1,1)
Is there a nice way to do it, rather than remove the head of the list and then use takeWhile on the remainder, and finally using dropwhile? I can think of simple non-functional solution but I was wondering whether any functional one also exists
The functional way to avoid the duplication of takeWhile and dropWhile to get a prefix and remainder is using span, i.e.
scala> val list = List(1,1,1,2,3,3)
list: List[Int] = List(1, 1, 1, 2, 3, 3)
scala> val (prefix, rest) = list span (_ == list.head)
prefix: List[Int] = List(1, 1, 1)
rest: List[Int] = List(2, 3, 3)
Is this what you look for?
scala> val l = List(1,1,1,2,3,3)
l: List[Int] = List(1, 1, 1, 2, 3, 3)
scala> l.takeWhile(_ == l.head)
res6: List[Int] = List(1, 1, 1)
scala> val l = List()
l: List[Nothing] = List()
scala> l.takeWhile(_ == l.head)
res7: List[Nothing] = List()
Not the best way of doing it, but this also works:
def removeSame(l: List) = if( !l.isEmpty) l.groupBy( x => x)(l.head) else List()

Scala list concatenation, ::: vs ++

Is there any difference between ::: and ++ for concatenating lists in Scala?
scala> List(1,2,3) ++ List(4,5)
res0: List[Int] = List(1, 2, 3, 4, 5)
scala> List(1,2,3) ::: List(4,5)
res1: List[Int] = List(1, 2, 3, 4, 5)
scala> res0 == res1
res2: Boolean = true
From the documentation it looks like ++ is more general whereas ::: is List-specific. Is the latter provided because it's used in other functional languages?
Legacy. List was originally defined to be functional-languages-looking:
1 :: 2 :: Nil // a list
list1 ::: list2 // concatenation of two lists
list match {
case head :: tail => "non-empty"
case Nil => "empty"
}
Of course, Scala evolved other collections, in an ad-hoc manner. When 2.8 came out, the collections were redesigned for maximum code reuse and consistent API, so that you can use ++ to concatenate any two collections -- and even iterators. List, however, got to keep its original operators, aside from one or two which got deprecated.
Always use :::. There are two reasons: efficiency and type safety.
Efficiency
x ::: y ::: z is faster than x ++ y ++ z, because ::: is right associative. x ::: y ::: z is parsed as x ::: (y ::: z), which is algorithmically faster than (x ::: y) ::: z (the latter requires O(|x|) more steps).
Type safety
With ::: you can only concatenate two Lists. With ++ you can append any collection to List, which is terrible:
scala> List(1, 2, 3) ++ "ab"
res0: List[AnyVal] = List(1, 2, 3, a, b)
++ is also easy to mix up with +:
scala> List(1, 2, 3) + "ab"
res1: String = List(1, 2, 3)ab
::: works only with lists, while ++ can be used with any traversable. In the current implementation (2.9.0), ++ falls back on ::: if the argument is also a List.
A different point is that the first sentence is parsed as:
scala> List(1,2,3).++(List(4,5))
res0: List[Int] = List(1, 2, 3, 4, 5)
Whereas the second example is parsed as:
scala> List(4,5).:::(List(1,2,3))
res1: List[Int] = List(1, 2, 3, 4, 5)
So if you are using macros, you should take care.
Besides, ++ for two lists is calling ::: but with more overhead because it is asking for an implicit value to have a builder from List to List. But microbenchmarks did not prove anything useful in that sense, I guess that the compiler optimizes such calls.
Micro-Benchmarks after warming up.
scala>def time(a: => Unit): Long = { val t = System.currentTimeMillis; a; System.currentTimeMillis - t}
scala>def average(a: () => Long) = (for(i<-1 to 100) yield a()).sum/100
scala>average (() => time { (List[Int]() /: (1 to 1000)) { case (l, e) => l ++ List(e) } })
res1: Long = 46
scala>average (() => time { (List[Int]() /: (1 to 1000)) { case (l, e) => l ::: List(e ) } })
res2: Long = 46
As Daniel C. Sobrai said, you can append the content of any collection to a list using ++, whereas with ::: you can only concatenate lists.

What is a DList?

I tried googling for this but all I got were stories about minor celebrities. Given the lack of documentation, what is a DList?
It's a Difference List, along the lines of "Difference List as functions"
scala> val (l1, l2, l3) = (List(1, 2, 3), List(4, 5, 6), List(7, 8, 9))
l1: List[Int] = List(1, 2, 3)
l2: List[Int] = List(4, 5, 6)
l3: List[Int] = List(7, 8, 9)
Efficient prepending:
scala> l1 ::: l2 ::: l3
res8: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9)
Inefficient appending. This creates an intermediate list (l1 ++ l2), then ((l1 ++ l2) ++ l3)
scala> l1 ++ l2 ++ l3 // inefficient
res9: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9)
DList stores up the appends, and only needs to create one complete list, effectively invoking:
scala> List(l1, l2, l3) reduceRight ( _ ::: _)
res10: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9)
Difference lists are a list-like data structure that supports O(1) append operations.
Append, and other operations that modify a list are represented via function composition of the modification functions, rather than directly copying the list.
An example, from Haskell's dlist library:
-- Lists as functions
newtype DList a = DL { unDL :: [a] -> [a] }
-- The empty list
empty = DL id
-- The append case: composition, a la Hughes
append xs ys = DL (unDL xs . unDL ys)
-- Converting to a regular list, linear time.
toList = ($[]) . unDL
The technique goes back at least to Hughes 84, A novel representation of lists and its application to the function "reverse", R. John Hughes, 1984., where, he proposes representing lists as functions, and append as function composition, allowing e.g. reverse to run in linear time. From the paper:
It's a data type in the non-canonical scalaz package, useful for typed lists with constant-time access at both ends. (The trick is to google for "scala" AND "dlist".)
From the project page of scalaz:
DList, a data type for representing elements of the same type with constant time append/prepend operations.