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.
Related
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).
I'm trying to do some arithmetic on a list that may contain missing values.
So far, I'm representing my list with Option[Int]:
val mylist=List( Option(4), Option(8), None )
With this representation, I can easily apply a function over the list (say, multiply by 2):
scala> mylist.map(_.map(_*2))
res2: List[Option[Int]] = List(Some(8), Some(16), None)
However, this looks more complicated than it needs be, so I'm wondering if I'm missing something.
Also, I can't figure out how to write things like the sum. I guess it should be possible with a (big) reduce expression...
So, I'd like to know if:
List[Option[Int]] is a good representation for this use case
mylist.map(_.map(_*2)) is the best way to map
is there a simple way to do a sum?
Well, it's not a pattern I've used myself, but if values can be "missing" then an Option is appropriate. But a List probably isn't. In a List the position isn't usually something you should be relying on, since it's not random-access. Maybe a Vector would be better, or you need to think of a better way of modelling your problem, i.e. not as a list with missing values.
You can deal with Option nicely using for-expressions:
for (o <- mylist; x <- o) yield x * 2
or flatten the list:
mylist.flatten.map(_ * 2)
To sum it:
mylist.flatten.sum
List[Option[Int]] is a good representation for this use case
Is it possible to flatten it earlier with flatMap? For example, if you are creating this list using map, you could use flatMap instead and not have missing values. My suggestion is to not even represent the missing values if possible. If you need to represent them, Option is ideal.
mylist.map(_.map(_*2)) is the best way to map
is there a simple way to do a sum?
The nested map is probably preferable. You can foldLeft also.
foldLeft is also helpful if you need to do something besides sum/product.
scala> val mylist=List( Option(4), Option(8), None )
mylist: List[Option[Int]] = List(Some(4), Some(8), None)
scala> mylist.foldLeft(0){
| case (acc, Some(i)) => acc + i
| case (acc, _) => acc
| }
res7: Int = 12
scala> (0 /: mylist) {
| case (acc, Some(i)) => acc + i
| case (acc, _) => acc
| }
res8: Int = 12
scala> (0 /: mylist) {
| case (acc, Some(i)) => acc - (i * 2)
| case (acc, _) => acc
| }
res16: Int = -24
So, I'd like to know if:
List[Option[Int]] is a good representation for this use case
Option is definitely the preferable way to express missing values. You could also think about changing it into a List[(Int, Int)] where the first element indicates the position in your original list and the second element represents the value.
mylist.map(_.map(_*2)) is the best way to map
In my opinion there is no shorter or cleaner way to express that. (You have two "levels" that's why you need two maps!) With my suggested data structure this would turn into mylist.map(t => (t._1, t._2*2)).
is there a simple way to do a sum?
No easier way than om-nom-nom suggested. With my data structure it would be mylist.map(_._2).sum
The most general and most concise way to do this is with Scalaz's semigroup type class. That way, you're not restricted to List[Option[Int]] but can apply the same function to List[Int].
import scalaz._
import Scalaz._
object S {
def double[A:Semigroup](l:List[A]) = l.map(x => x |+| x)
def sum[A:Semigroup](l:List[A]) = l.reduce(_ |+| _)
def main(a:Array[String]) {
val l = List(Some(1), None, Some(2))
val l2 = List(1,2)
println(double(l))
println(sum(l))
println(double(l2))
println(sum(l2))
}
}
This prints
List(Some(2), None, Some(4))
Some(3)
List(2, 4)
3
i'm not sure what it is you are trying to achieve, but this does'nt seem like the right approach. if you need to determine if a value exists in your "list", then perhapse a Set would suit your needs better:
scala> val s = Set(4,8)
s: scala.collection.immutable.Set[Int] = Set(4, 8)
scala> s(4)
res0: Boolean = true
scala> s(5)
res1: Boolean = false
scala> s map (_ * 2)
res2: scala.collection.immutable.Set[Int] = Set(8, 16)
scala> s reduceLeft((a,b) => a+b)
res3: Int = 12
or even easier:
scala> s sum
res4: Int = 12
if you need something more sophisticated, and the index of the element in your list is important, you may use a Map where the keys simulate the index, and missing values can be mapped to some default value:
scala> val m = Map(1 -> 4, 2 -> 8) withDefault(n => 0)
m: scala.collection.immutable.Map[Int,Int] = Map(1 -> 4, 2 -> 8)
scala> m(1)
res5: Int = 4
scala> m(3)
res6: Int = 0
scala> m map {case (k,v) => (k,2*v)}
res7: scala.collection.immutable.Map[Int,Int] = Map(1 -> 8, 2 -> 16)
scala> m.foldLeft(0){case (sum,(_,v)) => sum+v}
res8: Int = 12
again, not sure what your needs are, but it feels like you are going the wrong way...
Option is a type i would think twice before using. ask yourself if it's realy necessary. there might be solutions that would achieve what you are trying to do in a more elegant way.
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.
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.
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.