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.
Related
To get familiar with Scala lists I decided to implement flatten, which would take a list like: List(List(2,4), 22, List(1)) to List(2, 4, 22, 1).
When I attempted to run the code below
def flatify(xs: List[Any]) : List[Any] = {
xs match {
case Nil=> {
Nil
}
case x::rest if x.isInstanceOf[List[Any]] => {
flatify(x):: flatify(rest) // bad line
}
case x::rest => {
x:: flatify(rest)
}
case _ => {
throw new IllegalStateException("cant match")
}
}
}
var list = List(List(4, 5), 9, 10, List(1, 2))
flatify(list)
The compiler complained about the line commented as '// bad line', saying:
Error:(84, 17) type mismatch;
found : Any
required: List[Any]
flatify(x):: flatify(rest)
^
This strikes me as very odd, since my guard condition explicitly
requires x to be isInstanceOf[List[Any]]. I understand that
Any is a superclass of List[Any] but I would have thought that
once the compiler gets to the right hand side of the expression
flatify(x) :: flatify(rest)
it would accept that x is a List[Any].
I'm sure my implementation might have other problems as I have not
fully debugged it yet, but before I moved on I wanted to try to
understand what the Scala compiler was up to here. Any tips or
pointers are gratefully appreciated.
You're matching on a List[Any], so when you have
case x :: tail if(x.isInstanceOf[List[Any]]) => x ...
^ ^ ^
Any true, but the type of Still Any
x is already determined
x is Any and tail is List[Any]. The if condition does nothing change the type of x, even if you can test that x.isInstanceOf[List[Any]], x is still Any. You need to match on the type, itself.
def flatify(xs: List[Any]) : List[Any] = {
xs match {
case Nil => Nil
case (x: List[Any]) :: rest => flatify(x) ::: flatify(rest)
case x :: rest => x :: flatify(rest)
case _ => throw new IllegalStateException("cant match")
}
}
Furthermore, there is another bug. Given x correctly matched as List[Any], the following flatify(x) :: flatify(rest) will place a List[Any] at the head of a List[Any], and therefore does no flattening at all. So I changed it to :::.
scala> flatify(List(1,2,3,List(4,5,6), List(7,8,9)))
res1: List[Any] = List(1, 2, 3, 4, 5, 6, 7, 8, 9)
Scala's type system (just like Java's) does not change the type of a variable inside an if, even if the if condition was isInstanceOf. There are two ways to make your code work:
The Java way would be to use a cast to tell Scala that it's okay to use x as a list after you checked that it is indeed a list using isInstanceOf.
The Scala way is to just not use isInstanceOf at all, but rather use x : List[Any] in your pattern, which does make the static type of x List[Any], so x can be used as a list without a cast.
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.
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.
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.
I have a list l:List[T1] and currently im doing the following:
myfun : T1 -> Option[T2]
val x: Option[T2] = l.map{ myfun(l) }.flatten.find(_=>true)
The myfun function returns None or Some, flatten throws away all the None's and find returns the first element of the list if any.
This seems a bit hacky to me. Im thinking that there might exist some for-comprehension or similar that will do this a bit less wasteful or more clever.
For example: I dont need any subsequent answers if myfun returns any Some during the map of the list l.
How about:
l.toStream flatMap (myfun andThen (_.toList)) headOption
Stream is lazy, so it won't map everything in advance, but it won't remap things either. Instead of flattening things, convert Option to List so that flatMap can be used.
In addition to using toStream to make the search lazy, we can use Stream::collectFirst:
List(1, 2, 3, 4, 5, 6, 7, 8).toStream.map(myfun).collectFirst { case Some(d) => d }
// Option[String] = Some(hello)
// given def function(i: Int): Option[String] = if (i == 5) Some("hello") else None
This:
Transforms the List into a Stream in order to stop the search early.
Transforms elements using myFun as Option[T]s.
Collects the first mapped element which is not None and extract it.
Starting Scala 2.13, with the deprecation of Streams in favor of LazyLists, this would become:
List(1, 2, 3, 4, 5, 6, 7, 8).to(LazyList).map(function).collectFirst { case Some(d) => d }
Well, this is almost, but not quite
val x = (l flatMap myfun).headOption
But you are returning a Option rather than a List from myfun, so this may not work. If so (I've no REPL to hand) then try instead:
val x = (l flatMap(myfun(_).toList)).headOption
Well, the for-comprehension equivalent is pretty easy
(for(x<-l, y<-myfun(x)) yield y).headOption
which, if you actually do the the translation works out the same as what oxbow_lakes gave. Assuming reasonable laziness of List.flatmap, this is both a clean and efficient solution.
As of 2017, the previous answers seem to be outdated. I ran some benchmarks (list of 10 million Ints, first match roughly in the middle, Scala 2.12.3, Java 1.8.0, 1.8 GHz Intel Core i5). Unless otherwise noted, list and map have the following types:
list: scala.collection.immutable.List
map: A => Option[B]
Simply call map on the list: ~1000 ms
list.map(map).find(_.isDefined).flatten
First call toStream on the list: ~1200 ms
list.toStream.map(map).find(_.isDefined).flatten
Call toStream.flatMap on the list: ~450 ms
list.toStream.flatMap(map(_).toList).headOption
Call flatMap on the list: ~100 ms
list.flatMap(map(_).toList).headOption
First call iterator on the list: ~35 ms
list.iterator.map(map).find(_.isDefined).flatten
Recursive function find(): ~25 ms
def find[A,B](list: scala.collection.immutable.List[A], map: A => Option[B]) : Option[B] = {
list match {
case Nil => None
case head::tail => map(head) match {
case None => find(tail, map)
case result # Some(_) => result
}
}
}
Iterative function find(): ~25 ms
def find[A,B](list: scala.collection.immutable.List[A], map: A => Option[B]) : Option[B] = {
for (elem <- list) {
val result = map(elem)
if (result.isDefined) return result
}
return None
}
You can further speed up things by using Java instead of Scala collections and a less functional style.
Loop over indices in java.util.ArrayList: ~15 ms
def find[A,B](list: java.util.ArrayList[A], map: A => Option[B]) : Option[B] = {
var i = 0
while (i < list.size()) {
val result = map(list.get(i))
if (result.isDefined) return result
i += 1
}
return None
}
Loop over indices in java.util.ArrayList with function returning null instead of None: ~10 ms
def find[A,B](list: java.util.ArrayList[A], map: A => B) : Option[B] = {
var i = 0
while (i < list.size()) {
val result = map(list.get(i))
if (result != null) return Some(result)
i += 1
}
return None
}
(Of course, one would usually declare the parameter type as java.util.List, not java.util.ArrayList. I chose the latter here because it's the class I used for the benchmarks. Other implementations of java.util.List will show different performance - most will be worse.)