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.
Related
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.
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.
How can I convert a list with (say) 3 elements into a tuple of size 3?
For example, let's say I have val x = List(1, 2, 3) and I want to convert this into (1, 2, 3). How can I do this?
You can do it using scala extractors and pattern matching (link):
val x = List(1, 2, 3)
val t = x match {
case List(a, b, c) => (a, b, c)
}
Which returns a tuple
t: (Int, Int, Int) = (1,2,3)
Also, you can use a wildcard operator if not sure about a size of the List
val t = x match {
case List(a, b, c, _*) => (a, b, c)
}
You can't do this in a typesafe way. Why? Because in general we can't know the length of a list until runtime. But the "length" of a tuple must be encoded in its type, and hence known at compile time. For example, (1,'a',true) has the type (Int, Char, Boolean), which is sugar for Tuple3[Int, Char, Boolean]. The reason tuples have this restriction is that they need to be able to handle a non-homogeneous types.
an example using shapeless :
import shapeless._
import syntax.std.traversable._
val x = List(1, 2, 3)
val xHList = x.toHList[Int::Int::Int::HNil]
val t = xHList.get.tupled
Note: the compiler need some type informations to convert the List in the HList that the reason why you need to pass type informations to the toHList method
Shapeless 2.0 changed some syntax. Here's the updated solution using shapeless.
import shapeless._
import HList._
import syntax.std.traversable._
val x = List(1, 2, 3)
val y = x.toHList[Int::Int::Int::HNil]
val z = y.get.tupled
The main issue being that the type for .toHList has to be specified ahead of time. More generally, since tuples are limited in their arity, the design of your software might be better served by a different solution.
Still, if you are creating a list statically, consider a solution like this one, also using shapeless. Here, we create an HList directly and the type is available at compile time. Remember that an HList has features from both List and Tuple types. i.e. it can have elements with different types like a Tuple and can be mapped over among other operations like standard collections. HLists take a little while to get used to though so tread slowly if you are new.
scala> import shapeless._
import shapeless._
scala> import HList._
import HList._
scala> val hlist = "z" :: 6 :: "b" :: true :: HNil
hlist: shapeless.::[String,shapeless.::[Int,shapeless.::[String,shapeless.::[Boolean,shapeless.HNil]]]] = z :: 6 :: b :: true :: HNil
scala> val tup = hlist.tupled
tup: (String, Int, String, Boolean) = (z,6,b,true)
scala> tup
res0: (String, Int, String, Boolean) = (z,6,b,true)
Despite the simplicity and being not for lists of any length, it is type-safe and the answer in most cases:
val list = List('a','b')
val tuple = list(0) -> list(1)
val list = List('a','b','c')
val tuple = (list(0), list(1), list(2))
Another possibility, when you don't want to name the list nor to repeat it (I hope someone can show a way to avoid the Seq/head parts):
val tuple = Seq(List('a','b')).map(tup => tup(0) -> tup(1)).head
val tuple = Seq(List('a','b','c')).map(tup => (tup(0), tup(1), tup(2))).head
FWIW, I wanted a tuple to initalise a number of fields and wanted to use the syntactic sugar of tuple assignment.
EG:
val (c1, c2, c3) = listToTuple(myList)
It turns out that there is syntactic sugar for assigning the contents of a list too...
val c1 :: c2 :: c3 :: Nil = myList
So no need for tuples if you've got the same problem.
If you are very sure that your list.size<23 use it:
def listToTuple[A <: Object](list:List[A]):Product = {
val class = Class.forName("scala.Tuple" + list.size)
class.getConstructors.apply(0).newInstance(list:_*).asInstanceOf[Product]
}
listToTuple: [A <: java.lang.Object](list: List[A])Product
scala> listToTuple(List("Scala", "Smart"))
res15: Product = (Scala,Smart)
You can't do this in a type-safe way. In Scala, lists are arbitrary-length sequences of elements of some type. As far as the type system knows, x could be a list of arbitrary length.
In contrast, the arity of a tuple must be known at compile time. It would violate the safety guarantees of the type system to allow assigning x to a tuple type.
In fact, for technical reasons, Scala tuples were limited to 22 elements, but the limit no longer exists in 2.11 The case class limit has been lifted in 2.11 https://github.com/scala/scala/pull/2305
It would be possible to manually code a function that converts lists of up to 22 elements, and throws an exception for larger lists. Scala's template support, an upcoming feature, would make this more concise. But this would be an ugly hack.
This can also be done in shapeless with less boilerplate using Sized:
scala> import shapeless._
scala> import shapeless.syntax.sized._
scala> val x = List(1, 2, 3)
x: List[Int] = List(1, 2, 3)
scala> x.sized(3).map(_.tupled)
res1: Option[(Int, Int, Int)] = Some((1,2,3))
It's type-safe: you get None, if the tuple size is incorrect, but the tuple size must be a literal or final val (to be convertible to shapeless.Nat).
Using Pattern Matching:
val intTuple = List(1,2,3) match {case List(a, b, c) => (a, b, c)}
2015 post.
For the Tom Crockett's answer to be more clarifying, here is a real example.
At first, I got confused about it. Because I come from Python, where you can just do tuple(list(1,2,3)).
Is it short of Scala language ? (the answer is -- it's not about Scala or Python, it's about static-type and dynamic-type.)
That's causes me trying to find the crux why Scala can't do this .
The following code example implements a toTuple method, which has type-safe toTupleN and type-unsafe toTuple.
The toTuple method get the type-length information at run-time, i.e no type-length information at compile-time, so the return type is Product which is very like the Python's tuple indeed (no type at each position, and no length of types).
That way is proned to runtime error like type-mismatch or IndexOutOfBoundException. (so Python's convenient list-to-tuple is not free lunch. )
Contrarily , it is the length information user provided that makes toTupleN compile-time safe.
implicit class EnrichedWithToTuple[A](elements: Seq[A]) {
def toTuple: Product = elements.length match {
case 2 => toTuple2
case 3 => toTuple3
}
def toTuple2 = elements match {case Seq(a, b) => (a, b) }
def toTuple3 = elements match {case Seq(a, b, c) => (a, b, c) }
}
val product = List(1, 2, 3).toTuple
product.productElement(5) //runtime IndexOutOfBoundException, Bad !
val tuple = List(1, 2, 3).toTuple3
tuple._5 //compiler error, Good!
you can do this either
via pattern-matching (what you do not want) or
by iterating through the list and applying each element one by one.
val xs: Seq[Any] = List(1:Int, 2.0:Double, "3":String)
val t: (Int,Double,String) = xs.foldLeft((Tuple3[Int,Double,String] _).curried:Any)({
case (f,x) => f.asInstanceOf[Any=>Any](x)
}).asInstanceOf[(Int,Double,String)]
In scala 3, you can do something like this:
def totuple[A](as: List[A]): Tuple = as match
case Nil => EmptyTuple
case h :: t => h *: totuple(t)
but as has been said already, without giving the compiler any more hard-coded type information, you aren't going to know the length of the tuple or the types of its elements, so this is likely hardly any better than the original list.
as far as you have the type:
val x: List[Int] = List(1, 2, 3)
def doSomething(a:Int *)
doSomething(x:_*)
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).
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.