Run length encoding using Scala - list

Given a list of elements of which some are repeated multiple times, i need to produce a new list with tuples, where each tuple contains number of times an element is repeated in a row and an element itself.
For example, given
println(func(List())) // should be empty list
println(func(List(1, 1))) // (2,1) <- 1 is repeated 2 times
println(func(List(1, 1, 2, 1))) // (2,1)(1,2)(1,1)
This is my best attempt at this point. I feel that i am missing something very basic, please help me understand what
def func[X](xs: List[X]): List[(Int, X)] = xs match {
case Nil => Nil
case y :: ys => ys match {
case Nil => (1, y) :: Nil
case z :: zs => if (y != z) (ys.prefixLength(_ == ys.head), y) :: func(ys)
else func(ys)
}
}
After analyzing what the problem is, it seems to me that at the point when i recursively call func(ys), ys does not have enough information to figure out the count of elements. Say we're dealing with List(1,1,1,2). Ok, so, y is 1, z is 1 and (1::(2::Nil)) is zs. Following my logic above, the fact that 1 was seen 2 times is lost for the next call.
The problem may be that i am not thinking about the problem the right way. What i have in mind is "go along the list until you find that this element is not the same as a previous elements, at which point, count the number of occurrences of an element and make it into the tuple")
I recognize that in the above scenario (in my code) the problem is that when numbers are in fact the same (1,1) the fact that we already saw a number is not reflected anywhere. But where can this be done please, given that i am not yet ready to compose a tuple
In answering this question, please stick to case structure. I realize that there maybe other better, cleaner ways to address this problem, i would like to better understand what i am doing wrong here

You're on the right track. The problem is that you can't just incrementally build the result list here—you'll have to pull the head off the list you get from the recursive call and check whether you need to add a new pair or increment the count of the last one:
def func[X](xs: List[X]): List[(Int, X)] = xs match {
case Nil => Nil
case y :: ys => func(ys) match {
case (c, `y`) :: rest => (c + 1, y) :: rest
case rest => ( 1, y) :: rest
}
}
Note the backticks around y in the nested match pattern—this is necessary to avoid just defining a new variable named y.

Here's a simpler solution using span:
def runLength[T](xs: List[T]): List[(Int, T)] = xs match {
case Nil => List()
case x :: l => {
val (front, back) = l.span(_ == x)
(front.length + 1, x) :: runLength(back)
}
}

It is indeed run-length encoding.
Here's a straightforward, though generic,attempt...
package rrs.scribble
object RLE {
def rle[T](tSeq: List[T]): List[(Int, T)] = {
def doRLE(seqT: List[T], rle: List[(Int, T)]): List[(Int, T)] =
seqT match {
case t :: moreT if t == rle.head._2 => doRLE(moreT, (rle.head._1 + 1, t) :: rle.tail)
case t :: moreT => doRLE(moreT, (1, t) :: rle)
case Nil => rle
}
if (tSeq.isEmpty)
List.empty[(Int, T)]
else
doRLE(tSeq, List((0, tSeq.head))).reverse
}
}
In the REPL:
scala> import rrs.scribble.RLE._
import rrs.scribble.RLE._
scala> rle(List(1, 1, 2, 1))
res0: List[(Int, Int)] = List((2,1), (1,2), (1,1))

This is called run-length encoding. Check out problem 10 of 99 Scala Problems (click on the problem numbers for solutions).

Related

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.

filter a list of lists : basic thing

Do you know why this program does not give expected answer (List(3,3)) ?
val l=List(List(1,2),List(3,3))
println(l.filter(_ match{
case u::v => u==v
case _ => false
}))
thanks!
case u::v => u==v
Here, u is of type Int, while v is of type List[Int]. They cannot be equal.
An alternate way of coding this, that would be useful if you might be dealing with lists of arbitrary length and want to filter down to only those lists with all elements the same, would be:
l.filter(ls => !ls.isEmpty && ls.forall(_ == ls.head))
(the !ls.isEmpty fragment presumes you would wish to exclude empty lists)
If you want to extract the first two elements from your sublists and compare them, you need two :: in your case:
l.filter {
case u :: v :: _ => u == v
case _ => false
}
If you want to make sure all elements of the sublists are equal, you could use forall:
l.filter {
case h :: Nil => false // if you want to exclude single elements
case h :: r => r.forall(_ == h)
case _ => false
}
You need to check the documentation of class ::. The constructor argument it takes are (hd: B, tl: List[B])
In your case u becomes hd and v is List[In]. And doing u==v is like doing hd.equals(list) which gives wrong result.
scala> val l= List(List(1,2),List(3,3),List(1),List(1,2,3),List(4,4,4,4))
l: List[List[Int]] = List(List(1, 2), List(3, 3))
scala> l.filter(_ match{
case u::v => Some(u) == v.headOption
case _ => false
})
res8: List[List[Int]] = List(List(3, 3), List(4, 4, 4, 4))
The above is an idiomatic way of doing it.

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 to replace(fill) None entries on List of Options from another List using idiomatic Scala?

I have a List[Option[MyClass]] with None in random positions and I need to 'fill' that list again, from a List[MyClass], maintaining the order.
Here are sample lists and expected result:
val listA = List(Some(3),None,Some(5),None,None)
val listB = List(7,8,9)
val expectedList = List(Some(3), Some(7), Some(5), Some(8), Some(9))
So, how would be a idiomatic Scala to process that list?
def fillL[T](a:List[Option[T]], b:List[T]) = {
val iterB = b.iterator
a.map(_.orElse(Some(iterB.next)))
}
The iterator solution is arguably idiomatic Scala, and is definitely concise and easy to understand, but it's not functional—any time you call next on an iterator you're firmly in the land of side effects.
A more functional approach would be to use a fold:
def fillGaps[A](gappy: List[Option[A]], filler: List[A]) =
gappy.foldLeft((List.empty[Option[A]], filler)) {
case ((current, fs), Some(item)) => (current :+ Some(item), fs)
case ((current, f :: fs), None) => (current :+ Some(f), fs)
case ((current, Nil), None) => (current :+ None, Nil)
}._1
Here we move through the gappy list while maintaining two other lists: one for the items we've processed, and the other for the remaining filler elements.
This kind of solution isn't necessarily better than the other—Scala is designed to allow you to mix functional and imperative constructions in that way—but it does have potential advantages.
I'd just write it in the straightforward way, matching on the heads of the lists and handling each case appropriately:
def fill[A](l1: List[Option[A]], l2: List[A]) = (l1, l2) match {
case (Nil, _) => Nil
case (_, Nil) => l1
case (Some(x) :: xs, _) => Some(x) :: fill(xs, l2)
case (None :: xs, y :: ys) => Some(y) :: fill(xs, ys)
}
Presumably once you run out of things to fill it with, you just leave the rest of the Nones in there.

Scala insert into list at specific locations

This is the problem that I did solve, however being a total imperative Scala noob, I feel I found something totally not elegant. Any ideas of improvement appreciated.
val l1 = 4 :: 1 :: 2 :: 3 :: 4 :: Nil // original list
val insert = List(88,99) // list I want to insert on certain places
// method that finds all indexes of a particular element in a particular list
def indexesOf(element:Any, inList:List[Any]) = {
var indexes = List[Int]()
for(i <- 0 until inList.length) {
if(inList(i) == element) indexes = indexes :+ i
}
indexes
}
var indexes = indexesOf(4, l1) // get indexes where 4 appears in the original list
println(indexes)
var result = List[Any]()
// iterate through indexes and insert in front
for(i <- 0 until indexes.length) {
var prev = if(i == 0) 0 else indexes(i-1)
result = result ::: l1.slice(prev, indexes(i)) ::: insert
}
result = result ::: l1.drop(indexes.last) // append the last bit from original list
println(result)
I was thinking more elegant solution would be achievable with something like this, but that's just pure speculation.
var final:List[Any] = (0 /: indexes) {(final, i) => final ::: ins ::: l1.slice(i, indexes(i))
def insert[A](xs: List[A], extra: List[A])(p: A => Boolean) = {
xs.map(x => if (p(x)) extra ::: List(x) else List(x)).flatten
}
scala> insert(List(4,1,2,3,4),List(88,99)){_ == 4}
res3: List[Int] = List(88, 99, 4, 1, 2, 3, 88, 99, 4)
Edit: explanation added.
Our goal here is to insert a list (called extra) in front of selected elements in another list (here called xs--commonly used for lists, as if one thing is x then lots of them must be the plural xs). We want this to work on any type of list we might have, so we annotate it with the generic type [A].
Which elements are candidates for insertion? When writing the function, we don't know, so we provide a function that says true or false for each element (p: A => Boolean).
Now, for each element in the list x, we check--should we make the insertion (i.e. is p(x) true)? If yes, we just build it: extra ::: List(x) is just the elements of extra followed by the single item x. (It might be better to write this as extra :+ x--add the single item at the end.) If no, we have only the single item, but we make it List(x) instead of just x because we want everything to have the same type. So now, if we have something like
4 1 2 3 4
and our condition is that we insert 5 6 before 4, we generate
List(5 6 4) List(1) List(2) List(3) List(5 6 4)
This is exactly what we want, except we have a list of lists. To get rid of the inner lists and flatten everything into a single list, we just call flatten.
The flatten trick is cute, I wouldn't have thought of using map here myself. From my perspective this problem is a typical application for a fold, as you want go through the list and "collect" something (the result list). As we don't want our result list backwards, foldRight (a.k.a. :\) is here the right version:
def insert[A](xs: List[A], extra: List[A])(p: A => Boolean) =
xs.foldRight(List[A]())((x,xs) => if (p(x)) extra ::: (x :: xs) else x :: xs)
Here's another possibility, using Seq#patch to handle the actual inserts. You need to foldRight so that later indices are handled first (inserts modify the indices of all elements after the insert, so it would be tricky otherwise).
def insert[A](xs: Seq[A], ys: Seq[A])(pred: A => Boolean) = {
val positions = xs.zipWithIndex filter(x => pred(x._1)) map(_._2)
positions.foldRight(xs) { (pos, xs) => xs patch (pos, ys, 0) }
}