Using scala, I try to concatenate multiple elements to a list as follows
val min = func1()
val max = func1()
val interpol : List[Float] = func2()
val res : List[Float] = (min.toFloat) :: interpolated :: (max.toFloat) :: Nil
This syntax does not work because of a type mismatch error. How could I pre- and append elements to a list (in a very elegant way, i.e., without using list buffers, etc.)?
Btw, I also tried
val res : List[Float] = (min.toFloat) :: interpolated :: List(max.toFloat)
but got a type mismatch error (List[Any] vs List[Float])
The Peter Neyens solution works fine.
Personally, i prefer this one
min.toFloat +: interpolated :+ max.toFloat
+: and :+ are defines in Seq, so works not only for List, but for Vector too
You are prepending the min.toFloat to the interpolated list, but you can't prepend the resulting list to the list with the maximum you have created (max.toFloat :: Nil), you will need ::: to concatenate these two lists.
(min.toFloat) :: interpolated ::: ((max.toFloat) :: Nil)
Related
From the Book programming in Scala I got the following line of code:
val second: List[ Int] => Int = { case x :: y :: _ => y }
//warning: match may not be exhaustive.
It states that this function will return the second element of a list of integers if the list is not empty or nil. Stil this part is a bit awkward to me:
case x :: y :: _
How does this ecxactly work? Does this mathches any list with at least 2 Elements and than return the second? If so can somebody still explain the syntax? I understood that :: is invoked on the right operand. So it could be written as
(_.::(y)).::(X)
Still I than don't get why this would return 2
val second: List[ Int] => Int = { case x :: y :: _ => y }
var x = List(1,2)
second(x) //returns 2
In the REPL, you can type:
scala> val list = "a" :: "b" :: Nil
list: List[String] = List(a, b)
which is to be read from right to left, and means take the end of a List (Nil), prepend String "b" and to this List ("b" :: Nil) prepend String a, a :: ("b" :: Nil) but you don't need the parens, so it can be written "a" :: "b" :: Nil.
In pattern matching you will more often see:
... list match {
case Nil => // ...
case x :: xs => // ...
}
to distinguish between empty list, and nonempty, where xs might be a rest of list, but matches Nil too, if the whole list is ("b" :: Nil) for example, then x="b" and xs=Nil.
But if list= "a" :: "b" :: Nil, then x="a" and xs=(b :: Nil).
In your example, the deconstruction is just one more step, and instead of a name like xs, the joker sign _ is used, indicating, that the name is probably not used and doesn't play a role.
The value second is of function type, it takes List[Int] and returns Int.
If the list has first element ("x"), and a second element ("y"), and whatever comes next (we don't care about it), we simply return the element "y" (which is the second element of the list).
In any other case, the function is not defined. You can check that:
scala> val second: PartialFunction[List[Int], Int] = {
| case x :: y :: _ => y
| }
second: PartialFunction[List[Int],Int] = <function1>
scala> second.isDefinedAt(List(1,2,3))
res18: Boolean = true
scala> second.isDefinedAt(List(1,2))
res19: Boolean = true
scala> second.isDefinedAt(List(0))
res20: Boolean = false
First of all. When you think about pattern matching you should think about matching a structure.
The first part of the case statement describes a structure. This structure may describe one or more things (variables) which are useful to deriving your result.
In your example, you are interested in deriving the second element of a list. A shorthand to build a list in Scala is to use :: method (also called cons). :: can also be used to describe a structure in case statement. At this time, you shouldn't think about evaluation of the :: method in first part of case. May be that's why you are saying about evaluation of _.::(y).::(x). The :: cons operator help us describe the structure of the list in terms of its elements. In this case, the first element (x) , the second element (y) and the rest of it (_ wildcard). We are interested in a structure that is a list with at least 2 elements and the third can be anything - a Nil to indicate end of list or another element - hence the wildcard.
The second part of the case statement, uses the second element to derive the result (y).
More on List and Consing
List in Scala is similar to a LinkedList. You know about the first element called head and start of the rest of the list. When traversing the linked list you stop if the rest of the list is Nil. This :: cons operator helps us visualise the structure of the linked list. Although Scala compile would actually be calling :: methods evaluating from right to left as you described _.::(y).::(x)
As an aside, you might have already noticed that the Scala compiler might be complain that your match isn't exhaustive. This means that this second method would work for list of any size. Because there isn't any case statement to describe list with zero or one element. Also, as mentioned in comments of previous answers, if you aren't interested in first element you can describe it as a wildcard _.
case _ :: y :: _ => y
I hope this helped.
If you see the structure of list in scala its head::tail, first element is treated as head and all remaining ones as tail(Nil will be the last element of tail). whenever you do x::y::_, x will match the head of the list and remaining will be tail and again y will match the head of the next list(tail of first list)
eg:
val l = List(1,2,3,4,5)
you can see this list in differnt ways:
1::2::3::4::5::Nil
1::List(2,3,4,5)
1::2::List(2,3,4,5)
and so on
So try matching the pattern. In your question y will give the second element
I am newbie to scala and just trying out stuff, below is what I am trying
scala> var col = List[String]()
col: List[String] = List()
scala> List("a", "b", "c").foreach(x => x :: col)
scala> println(col)
List()
Actually, I was expecting col to contain a,b,c, what am I missing?
You need an assignment in the foreach
scala> var col = List[String]()
col: List[String] = List()
scala> List("a", "b", "c").foreach(x => {col = x :: col})
scala> col
res0: List[String] = List(c, b, a)
The operation x :: col simply returns a new list consisting of the element x prepended to col, the original col is not changed. You would need to reassign col to this newly generated list.
Note however that this would not typically be considered idiomatic Scala since you are using side-effects.
The :: method on list does not add anything to the list, it creates a new list with the value prepended to it, you are discarding this new list instead of reassigning it to col. x => col = x :: col will add each element of your list to col. Note that col will then be List("c","b","a"), the order is reversed because you are pre-pending the elements to col.
Note that foreach returns nothing and is designed for side-effecting operations. If you simply want to transform a collection or load elements into another collection there are better methods to use.
For your specific operation, the most appropriate method is foldRight which iterates elements in reverse order, right-to-left. We want to iterate in reverse here because when you prepend elements to a list one at a time the order gets reversed.
val col = List("a", "b", "c").foldRight(List[String]())((x, acc) => x :: acc) will produce a List("a", "b", "c"). This has the advantage that we no longer need to use var to declare a mutable variable, and in fact we don'
to need to declare our list ahead of time at all.
note, we could have used some special syntax to save some typing
val col = List("a", "b", "c").foldRight(List[String]())(_ :: _)
The underscores give us a shorter syntax to write function literals, I'll leave up to you to decide if it's more clear or not.
I am currently facing the following issue.
I have code that essentially has the following cases:
val toList = this.toString.match {
case "" => List[MyType]()
case _ => this.val :: this.prev.toList
}
Obviously not exact but its the general gist. It works fine but I want the values appended to the list in the reverse order. Is there any good way to do this? Intellij throws errors if I try to reverse the order and do
this.prev.toList :: this.val
and also if I try to use operations like ++. Is what I'm trying to do impossible based on the structure of my class?
The specific errors I get involve "cannot resolve ::" or whatever symbol I use when I try to put this.prev.toList before this.val.
And yes the "this" aren't necessary- I included it to hopefully make my problem easier to understand.
:: adds an element at the beginning of this list
scala> 1 :: List(2,3)
List(1, 2, 3)
+: is the equivalent of ::
scala> 1 +: List(2,3)
List(1, 2, 3)
:+ append element at the end of the list
scala> List(1,2) :+ 3
List(1, 2, 3)
However the cost of prepending on List is O(1) but the appending one is O(n)!
For "numerous" collections you could consider other datastructure like Vector:
Vector provides very fast append and prepend
http://www.scala-lang.org/api/2.11.7/index.html#scala.collection.immutable.Vector
You can append with this method :+:
this.prev.toList :+ this.val // is `val` really then name?
But keep in mind that appending to a List can be very inefficient for long lists.
If I have a function List[A] => List[List[A]] and need to return an "empty" value, is there a theoretical preference between the following
a) Nil
b) List(Nil)
... or does it depend on the function?
For a concrete example, I could implement a function to split a list into sublists of length n or less as follows:
def sublists[A](xs: List[A], n: Int): List[List[A]] = {
val (ys, zs) = xs.splitAt(n)
if (zs.isEmpty) ys :: Nil
else ys :: sublists(zs, n)
}
If xs is empty this returns List(Nil). Do I need to include a check on whether xs is empty, returning Nil, for this function to be correct?
Without doubt, the correct empty value for a List is the empty List, no matter what the type of the List elements is.
The same is true for more elaborated types. A set containing the empty set is very different from an empty set, and so forth.
Think of it like this: A list result allows you to ask: how many results do we have? If you use a list with an empty List as empty value, then the answer would be incorrectly 1.
I would stick with Nil, aka List(). For example,
sublists(1 :: 2 :: 3 :: 4 :: Nil), 2)
returns
List(1 :: 2 :: Nil, 3 :: 4 :: Nil)
and not
List(1 :: 2 :: Nil, 3 :: 4 :: Nil, Nil)
The terminal Nil is usually chopped off. So for consistency I would keep sublists(Nil) -> List().
I don't know the context, so I don't feel comfortable being definitive. In general, I think the answer is context-dependent. In the abstract, I'd definitely prefer Nil as a client-code writer - in writing a closure over the results, I don't think I'd be expecting an empty sublist.
Rearranging to put the null-check before the splitAt will do the trick.
I am matching a text file which has some columns [String Double Double Double Double]. I would like to obtain the following for each row of the file [String Double Double] and [String Double Double] wherein the String is the label same for both but I am splitting the first two doubles and last two doubles into two independent rows.
I am using the following which is not working:
val out = Source.fromFile(filename).getLines.collect(_.split("\\s+").toList match {
case s1 :: points1 :: points2 => (s1,"4",Point(points1.map(_.toDouble).toIndexedSeq))
=> (s1,"6",Point(points2.map(_.toDouble).toIndexedSeq))
My doubles are co-ordinates of points.
First of all points1 matches your second column and points2 rest columns.
It's because in :: notation left side is first element of list (head), but second is rest sublist (tail).
It may be easy to decompose row to list of all columns like this:
... match {
case s1 :: p1x :: p1y :: p2x :: p2y :: Nil =>
Then you can compose it again to two rows, placing them in two-element list:
=> List( (s1,"4",Point(Vector(p1x,p1y).map(_.toDouble))),
(s1,"6",Point(Vector(p2x,p2y).map(_.toDouble))) )
But then, in result you'll have a List[List[..]], so you need to flatten it. Simplest way is to use flatMap instead of collect.
So your full code will look like this:
val out = Source.fromFile(filename).getLines.flatMap(_.split("\\s+").toList match {
case s1 :: p1x :: p1y :: p2x :: p2y :: Nil =>
List( (s1,"4",Point(Vector(p1x,p1y).map(_.toDouble))),
(s1,"6",Point(Vector(p2x,p2y).map(_.toDouble))) )
})