Pattern matching list prefixes in Scala - list

I have questions regarding pattern matching of list prefixes (i.e. the first couple of elements of a list).
This compiles, but it does not work as expected:
val l = List(1,2,3)
val test = { m: List[Int] =>
m match {
case l :: tail => println("tail: "+tail.mkString(","))
case _ => println("no match")
}
}
test(List(1,2,3,4,5))
Output is tail: 2,3,4,5. I'd expect it to say either tail: 4,5, or to fail to match, or to fail at compile time. What makes this work as it does?
My second question is: How can I match a list prefix using a list? I know that this works as I expect:
case 1 :: 2 :: 3 :: tail => println("tail: "+tail.mkString(","))
I have, however, my prefixes as lists, and cannot hard-code them. Is pattern matching even the right thing here?
I know I could do something like
if (m startsWith l) {
val tail = m drop l.size
}
But a long list of these seems rather inelegant, especially in Scala.

Regarding the output of your first code snippet, the l inside of the match is actually a new value that shadows the outer scoped l and captures 1 during execution.
The problem you are encountering is that :: is the unapply for List to break it into exactly a single head value and the tail, deconstructing the linked list.
While there is a ::: operation to go along with ::: to concatenate two lists, it does not have a corresponding unapply which would let you use it in a pattern match in the way you desire.

I don't think this is possible. Closest syntax i could propose based on this workaround:
import collection.SeqLike
implicit class PrefixMatcher[T](prefix: Seq[T]) {
object then {
def unapply[S <: SeqLike[T,S]](seq: S): Option[S] =
if (seq startsWith prefix) Some(seq drop prefix.length) else None
}
}
Then you could use it as
val test: List[Int] => Unit = {
case l.then(tail) => println("tail: " + tail.mkString(","))
case _ => println("no match")
}

Addresing the first part of your question: As #Arne mentions, case l is not being matched against your list, but captures a new list. For the former you'd need to enclose it on backticks, but even then I don't see how you can achieve what you want, the closes I can think of is:
case `l` :+ x => println(s"tail is $s") //but this just works when the tail is just one element long.
For the final part of your question, maybe pattern matching is not the right thing to do here, how about:
val prefixes = List (List (1,2,3), List(4,5,6)...)
def findTail(li:List[Int]) = prefixes.collectFirst{ case p if li.startsWith(p) => li.drop(p.size) } //Option[List[Int]]
This will find the tail for the first prefix that matches the testList or None if there was no match.You can easily generalize it to work with more than just Ints.

Related

(Scala) Keeping the structure of a list in the output

I need a little assistance.
I've been working out the functional aspects in Scala. Almost all the work is in lists and for the most part, I can work out the problems, but I hit a small dead-end. I can't keep the original form (structure) of the list in certain problems. In the output all the nested lists get flattened. Concatenate ::: flattens the list(that is an element of the original list) and append :: gives me a compilation error, as it requires a generic T type (not a list).
A very simple example, in which I want to remove the first element of a list that matches the input:
def removeFirst[T](obj: T, list: List[T]): List[T] = {
if (list isEmpty) Nil
else{
val fin: List[T] = list.head match {
case headAsList: List[T] => if (containsWithNestedLists(obj, headAsList))
removeFirst(obj, headAsList) ::: list.tail
else headAsList ::: removeFirst(obj, list.tail)
case _ => if (list.head == obj) list.tail
else if (list.tail == List()) List(list.head)
else list.head :: removeFirst(obj, list.tail)
}
fin
}
}
For one level deep lists, it works fine, but
the output that comes out for
removeFirst(1,List(List(1,2,3),1,2,3,4,5,6)) is List(2, 3, 1, 2, 3, 4, 5, 6), where as ideally I would want List(List(2,3),1,2,3,4,5,6)).
Or the more specific input removeFirst(1,List(List(2,3,List()),List(1,2,3),1,2,3,4,5,6,List(2,3,List())))
should have output = List(List(2,3,List()),List(2,3),1,2,3,4,5,6,List(1,2,3,List()))
Also I have found that removing the generic T and using Any in its place does the trick, but I also know that Any is a big no-no and a temporary solution for a permanent problem, as in other functions it hasn't helped.
As far as I know, I haven't seen a helpful solution on the internet, so I have to ask. Am I missing something, need to debug or is there another function that could help me? The closest I've come to my answer is using append :: in some manner, but I may be wrong.
You examples just look as if you want to remove a certain element from the list if it is present.
For flat lists you can do this much simpler:
def removeFirst[T](obj: T, list: List[T]) = list match {
case `obj` :: rest => rest
case _ => list
}
This will do the following:
> removeFirst(1, List(1, List(1,2,3)))
res57: List[Any] = List(List(1, 2, 3))
> removeFirst(1, List(2, List(1,2,3)))
res58: List[Any] = List(2, List(1, 2, 3))
> removeFirst(List(2,3), List(List(2,3), List(1,2,3)))
res59: List[List[Int]] = List(List(1, 2, 3))
However, it seems you want to do this for arbitrarily nested Lists. This is not directly possible, as Scala cannot express the exact type of that. The type you'd need would be something like
type NestedList[T] = List[T union NestedList[T]]
Scala does not have union types and you cannot do recursive definitions in this way, so you can not just do this either:
type NestedList[T] = List[Either[T, NestedList[T]]]
You can however do it, if you use a class instead of a type:
case class NestedList[T](value: List[Either[T, NestedList[T]]])
Now you can write your algorithm like this:
def removeFirst[T](obj: T, list: NestedList[T]): NestedList[T] = {
val rest = list.value match {
case Left(`obj`) :: tail => tail
case __ => list.value
}
NestedList(rest.map {
case Right(r) => Right(removeFirst(obj, r))
case Left(r) => Left(r)
})
}
And you can do this:
> removeFirst(1, NestedList(List(Left(1), Left(2), Right(NestedList(List(Left(1),Left(3)))))))
res71: NestedList[Int] = NestedList(List(Left(2), Right(NestedList(List(Left(3))))))
It is of course a bit cumbersome to build and decompose these structures. So maybe it would be better to build a proper tree class using a sealed abstract class and two case classes instead of using the Either.

Finding the nth element of a list in scala recursively with pattern matching

I have a problem here from 99 scala problems (http://aperiodic.net/phil/scala/s-99/p03.scala) that I am trying to figure out how it works. I'm fairly new to Scala. I was able to complete this challenge with a similar solution using pattern matching and recursion however mine did not consider the list in the matching. My code is below:
def nth[A](k: Int, l: List[A]): A = k match {
case 0 => l.head
case _ => nth(k-1, l.drop(1))
}
and this seemed to do the job. However, there's no error checking if the list is Nil. The solution 99 scala problems provides is:
def nthRecursive[A](n: Int, ls: List[A]): A = (n, ls) match {
case (0, h :: _ ) => h
case (n, _ :: tail) => nthRecursive(n - 1, tail)
case (_, Nil ) => throw new NoSuchElementException
}
What I dont understand is
case(0, h:: _ )
and
case(n, _ :: tail)
What is the author doing here? I understand :: appends whatever is on the left to the beginning of whats on the right but I'm not sure exactly what is happening. Can anyone enlighten me?
Thank you!
The :: operator is used to extract the head and the rest of the list (the tail).
Here:
case(0, h :: _ )
only the head is relevant so the tail doesn't get a reference.
And Here:
case(n, _ :: tail)
only the tail is relevant so the head doesn't get a reference.
You can also use:
case(0, head :: tail)
case(n, head :: tail)
(i.e. giving both parts a reference) and get exactly the same result.
Basically, it is pattern matching expression. That is why Scala pattern matching is so powerful, so we can drop some heavy visitor pattern like Java (out of this topic).
A simple example:
case class User(name: String, age: Int)
def doStuff(user: User) = user match {
case User(_, age) if age > 100 => println("Impossible!")
case User(name, _) => println("hello " + name)
}
In this case, _ :: tail just means I want to get the reference of the tail.

Scala for loop Replace on List

Maybe this might be easy to fix but can you help me out or guide me to a solution. I have a remove function that goes through a List of tuples "List[(String,Any)]" and im trying to replace the 1 index of the value with Nil when the list is being looped over.
But when I try to replace the current v with Nil, it say the v is assigned to "val". Now I understand that scala lists are immutable. So maybe this is what is going wrong?
I tried a Tail recursion implementation as will but when I get out of the def there is a type mismatch. ie: is unit but required: Option[Any]
// remove(k) removes one value v associated with key k
// from the dictionary, if any, and returns it as Some(v).
// It returns None if k is associated to no value.
def remove(key:String):Option[Any] = {
for((k,v) <- d){
if(k == key){
var temp:Option[Any] = Some(v)
v = Nil
return temp
}
}; None
}
Here was the other way of trying to figure out
def remove(key:String):Option[Any] = {
def removeHelper(l:List[(String,Any)]):List[(String,Any)] =
l match {
case Nil => Nil
case (k,v)::t => if (key == k) t else (k,v)::removeHelper(t)
}
d = removeHelper(d)
}
Any Suggestions? This is a homework/Project for school thought I might add that for the people that don't like to help with homework.
Well, there are many ways of answering that question. I'll be outlining the ones I can think of here with my own implementations, but the list is by no means exhaustive (nor, probably, the implementations optimal).
First, you can try with existing combinators - the usual suspects are map, flatMap, foldLeft and foldRight:
def remove_flatMap(key: String, list: List[(String, Any)]): List[(String, Any)] =
// The Java developer in me rebels against creating that many "useless" instances.
list.flatMap {a => if(a._1 == key) Nil else List(a)}
def remove_foldLeft(key: String, list: List[(String, Any)]): List[(String, Any)] =
list.foldLeft(List[(String, Any)]()) {(acc, a) =>
if(a._1 == key) acc
else a :: acc
// Note the call to reverse here.
}.reverse
// This is more obviously correct than the foldLeft version, but is not tail-recursive.
def remove_foldRight(key: String, list: List[(String, Any)]): List[(String, Any)] =
list.foldRight(List[(String, Any)]()) {(a, acc) =>
if(a._1 == key) acc
else a :: acc
}
The problem with these is that, as far as I'm aware, you cannot stop them once a certain condition has been reached: I don't think they solve your problem directly, since they remove all instances of key rather than the first.
You also want to note that:
foldLeft must reverse the list once it's done, since it appends elements in the "wrong" order.
foldRight doesn't have that flaw, but is not tail recursive: it will cause memory issues on large lists.
map cannot be used for your problem, since it only lets us modify a list's values but not its structure.
You can also use your own implementation. I've included two versions, one that is tail-recursive and one that is not. The tail-recursive one is obviously the better one, but is also more verbose (I blame the ugliness of using a List[(String, Any)] rather than Map[String, Any]:
def remove_nonTailRec(key: String, list: List[(String, Any)]): List[(String, Any)] = list match {
case h :: t if h._1 == key => t
// This line is the reason our function is not tail-recursive.
case h :: t => h :: remove_nonTailRec(key, t)
case Nil => Nil
}
def remove_tailRec(key: String, list: List[(String, Any)]): List[(String, Any)] = {
#scala.annotation.tailrec
def run(list: List[(String, Any)], acc: List[(String, Any)]): List[(String, Any)] = list match {
// We've been aggregating in the "wrong" order again...
case h :: t if h._1 == key => acc.reverse ::: t
case h :: t => run(t, h :: acc)
case Nil => acc.reverse
}
run(list, Nil)
}
The better solution is of course to use the right tool for the job: a Map[String, Any].
Note that I do not think I answer your question fully: my examples remove key, while you want to set it to Nil. Since this is your homework, I'll let you figure out how to change my code to match your requirements.
List is the wrong collection to use if any key should only exist once. You should be using Map[String,Any]. With a list,
You have to do extra work to prevent duplicate entries.
Retrieval of a key will be slower, the further down the list it appears. Attempting to retrieve a non-existent key will be slow in proportion to the size of the list.
I guess point 2 is maybe why you are trying to replace it with Nil rather than just removing the key from the list. Nil is not the right thing to use here, really. You are going to get different things back if you try and retrieve a non-existent key compared to one that has been removed. Is that really what you want? How much sense does it make to return Some(Nil), ever?
Here's a couple of approaches which work with mutable or immutable lists, but which don't assume that you successfully stopped duplicates creeping in...
val l1: List[(String, Any)] = List(("apple", 1), ("pear", "violin"), ("banana", Unit))
val l2: List[(Int, Any)] = List((3, 1), (4, "violin"), (7, Unit))
def remove[A,B](key: A, xs: List[(A,B)]) = (
xs collect { case x if x._1 == key => x._2 },
xs map { case x if x._1 != key => x; case _ => (key, Nil) }
)
scala> remove("apple", l1)
res0: (List[(String, Any)], List[(String, Any)]) = (List((1)),List((apple, List()),(pear,violin), (banana,object scala.Unit)))
scala> remove(4, l2)
res1: (List[(Int, Any)], List[(Int, Any)]) = (List((violin)),List((3,1), (4, List()), (7,object scala.Unit)))
scala> remove("snark", l1)
res2: (List[Any], List[(String, Any)]) = (List(),List((apple,1), (pear,violin), (banana,object scala.Unit)))
That returns a list of matching values (so an empty list rather than None if no match) and the remaining list, in a tuple. If you want a version that just completely removes the unwanted key, do this...
def remove[A,B](key: A, xs: List[(A,B)]) = (
xs collect { case x if x._1 == key => x._2 },
xs filter { _._1 != key }
)
But also look at this:
scala> l1 groupBy {
case (k, _) if k == "apple" => "removed",
case _ => "kept"
}
res3: scala.collection.immutable.Map[String,List[(String, Any)]] = Map(removed -> List((apple,1)), kept -> List((pear,violin), (banana,object scala.Unit)))
That is something you could develop a bit. All you need to do is add ("apple", Nil) to the "kept" list and extract the value(s) from the "removed" list.
Note that I am using the List combinator functions rather than writing my own recursive code; this usually makes for clearer code and is often as fast or faster than a hand-rolled recursive function.
Note also that I don't change the original list. This means my function works with both mutable and immutable lists. If you have a mutable list, feel free to assign my returned list as the new value for your mutable var. Win, win.
But please use a map for this. Look how simple things become:
val m1: Map[String, Any] = Map(("apple", 1), ("pear", "violin"), ("banana", Unit))
val m2: Map[Int, Any] = Map((3, 1), (4, "violin"), (7, Unit))
def remove[A,B](key: A, m: Map[A,B]) = (m.get(key), m - key)
scala> remove("apple", m1)
res0: (Option[Any], scala.collection.immutable.Map[String,Any]) = (Some(1),Map(pear -> violin, banana -> object scala.Unit))
scala> remove(4, m2)
res1: (Option[Any], scala.collection.immutable.Map[Int,Any]) = (Some(violin),Map(3 -> 1, 7 -> object scala.Unit))
scala> remove("snark", m1)
res2: res26: (Option[Any], scala.collection.immutable.Map[String,Any]) = (None,Map(apple -> 1, pear -> violin, banana -> object scala.Unit))
The combinator functions make things easier, but when you use the right collection, it becomes so easy that it is hardly worth writing a special function. Unless, of course, you are trying to hide the data structure - in which case you should really be hiding it inside an object.

Pattern matching on a list in Scala

I'm a little confused regarding pattern matching on a list in Scala.
For example.
val simplelist: List[Char] = List('a', 'b', 'c', 'd')
//> simplelist : List[Char] = List(a, b, c, d)
def simple_fun(list: List[Char]) = list match {
case (x:Char) :: (y:List[Char]) => println(x)
case _ => Nil
}
//> simple_fun: (list: List[Char])Any
simple_fun(simplelist)
//> a
//| res0: Any = ()
This currently prints only one line of output. Should it not run/pattern match on each element of the List ?
EDIT: I fixed the compile errors and copied the output from the REPL.
Unless you are repeatedly calling simple_fun in some way, what you have there will pattern match the first element and nothing more. To get it to match the whole list, you can get simple_fun to call itself recursively, like this:
val simplelist: List[Char] = List('a', 'b', 'c', 'd')
def simple_fun(list: List[Char]): List[Nothing] = list match {
case x :: xs => {
println(x)
simple_fun(xs)
}
case _ => Nil
}
Note I've also left out some of the types as the Scala compiler can infer them, leaving you with less cluttered, more readable code.
As a small side-note, calling println repeatedly inside the function like that is not particularly functional - as it is all about side effects. A more idiomatic approach would be to have the function construct a string describing the list, which is then output with a single call to println - so the side-effects are kept in a single well-defined place. Something like this would be one approach:
def simple_fun(list: List[Char]):String = list match {
case x :: xs => x.toString + simple_fun(xs)
case Nil => ""
}
println(simple_fun(simple_list))
I would also like to mention that the case for lists can be divided not only the head and tail, as well as any N number of list elements:
def anyFunction(list: List[Int]): Unit =
list match {
// ...methods that have already been shown
case first :: second :: Nil => println(s"List has only 2 elements: $first and $second")
case first :: second :: tail => println(s"First: $first \nSecond: $second \nTail: $tail")
}
Hope it will be useful to someone.
I think the following should work:
def flatten(l: List[_]): List[Any] = l match {
case Nil => Nil
case (head: List[_]) :: tail => flatten(head) ::: flatten(tail)
case head :: tail => head :: flatten(tail)
}
The first line is a match for Nil, so if we don't find anything return nothing.
The second line will identify List of Lists and recall the flatten method and flatten the list of lists.

How should I remove the first occurrence of an object from a list in Scala?

What is the best way to remove the first occurrence of an object from a list in Scala?
Coming from Java, I'm accustomed to having a List.remove(Object o) method that removes the first occurrence of an element from a list. Now that I'm working in Scala, I would expect the method to return a new immutable List instead of mutating a given list. I might also expect the remove() method to take a predicate instead of an object. Taken together, I would expect to find a method like this:
/**
* Removes the first element of the given list that matches the given
* predicate, if any. To remove a specific object <code>x</code> from
* the list, use <code>(_ == x)</code> as the predicate.
*
* #param toRemove
* a predicate indicating which element to remove
* #return a new list with the selected object removed, or the same
* list if no objects satisfy the given predicate
*/
def removeFirst(toRemove: E => Boolean): List[E]
Of course, I can implement this method myself several different ways, but none of them jump out at me as being obviously the best. I would rather not convert my list to a Java list (or even to a Scala mutable list) and back again, although that would certainly work. I could use List.indexWhere(p: (A) ⇒ Boolean):
def removeFirst[E](list: List[E], toRemove: (E) => Boolean): List[E] = {
val i = list.indexWhere(toRemove)
if (i == -1)
list
else
list.slice(0, i) ++ list.slice(i+1, list.size)
}
However, using indices with linked lists is usually not the most efficient way to go.
I can write a more efficient method like this:
def removeFirst[T](list: List[T], toRemove: (T) => Boolean): List[T] = {
def search(toProcess: List[T], processed: List[T]): List[T] =
toProcess match {
case Nil => list
case head :: tail =>
if (toRemove(head))
processed.reverse ++ tail
else
search(tail, head :: processed)
}
search(list, Nil)
}
Still, that's not exactly succinct. It seems strange that there's not an existing method that would let me do this efficiently and succinctly. So, am I missing something, or is my last solution really as good as it gets?
You can clean up the code a bit with span.
scala> def removeFirst[T](list: List[T])(pred: (T) => Boolean): List[T] = {
| val (before, atAndAfter) = list span (x => !pred(x))
| before ::: atAndAfter.drop(1)
| }
removeFirst: [T](list: List[T])(pred: T => Boolean)List[T]
scala> removeFirst(List(1, 2, 3, 4, 3, 4)) { _ == 3 }
res1: List[Int] = List(1, 2, 4, 3, 4)
The Scala Collections API overview is a great place to learn about some of the lesser known methods.
This is a case where a little bit of mutability goes a long way:
def withoutFirst[A](xs: List[A])(p: A => Boolean) = {
var found = false
xs.filter(x => found || !p(x) || { found=true; false })
}
This is easily generalized to dropping the first n items matching the predicate. (i<1 || { i = i-1; false })
You can also write the filter yourself, though at this point you're almost certainly better off using span since this version will overflow the stack if the list is long:
def withoutFirst[A](xs: List[A])(p: A => Boolean): List[A] = xs match {
case x :: rest => if (p(x)) rest else x :: withoutFirst(rest)(p)
case _ => Nil
}
and anything else is more complicated than span without any clear benefits.