Scala List methods: `remove` and `sort` - scala

I'm working out of "Programming in Scala (First Edition)", and I've gotten to some List methods. There are two methods it names that give me an error in the interactive shell: remove and sort. Here are the examples it gives:
val thrill = "will" :: "fill" :: "until" :: Nil
thrill.sort((a, b) a.charAt(0).toLowerCase < b.charAt(0).toLowerCase)
thrill.remove(s => s.length == 4)
When I try those in the console, I get errors that those methods aren't "a member of List[String]":
scala> util.Properties.versionString
res41: String = version 2.11.1
scala> val myList = "one" :: "two" :: "three" :: "four" :: Nil
myList: List[String] = List(one, two, three, four)
scala> myList.sort((a, b) => a.charAt(0).toLowerCase < b.charAt(0).toLowerCase)
<console>:9: error: value sort is not a member of List[String]
myList.sort((a, b) => a.charAt(0).toLowerCase < b.charAt(0).toLowerCase)
^
scala> thrill.remove(s => s.length == 5)
<console>:9: error: value remove is not a member of List[String]
thrill.remove(s => s.length == 5)
So I thought maybe I was using a newer version (since this book appears to be written a few years back), and I consulted the List documentation. Both methods appear to be there in version 2.7.7 (the newest I could find). As you can see, I'm running 2.11.1.
Did these methods get remove from the List API since 2.7.7, or am I using them wrong?

In the darker times of scala 2.7 (it's more than four years ago!) your code would work just fine, but now, with 2.8+ you have to use different names for remove and sort:
import Character.{toLowerCase => lower}
myList.sortWith { case (a, b) => lower(a.charAt(0)) < lower(b.charAt(0)) }
// List(four, one, two, three)
There is also .sorted for default sorting
List(2, 5, 3).sorted
// res10: List[Int] = List(2, 3, 5)
and .sortBy(x => ...) to sort with some preparation (it's like sorted with ephemeral map):
val foo = List("ac", "aa", "ab")
foo.sortBy(x => x.charAt(1))
// res6: List[String] = List(aa, ab, ac)
And remove was replaced with filterNot (though, I think remove is more convinient name, even if it makes you think that collection is mutable, which is tricked Ven in his answer):
thrill.filterNot(s => s.length == 5)
// res9: List[String] = List(will, fill)
There is also, .filter, which does the opposite:
thrill.filter(s => s.length == 5)
// res11: List[String] = List(until)
It can be seen way more frequently in scala code.

Related

Why does For Comprehension generator suppress Option type?

In the code below, version 1 gives the correct result. I make a small variation in V2. The None value had disappeared which is Ok as that is how For Expression works. But what is the reason the yield output in V2 no longer respects the data type returned by myList.lift() which is an Option (as in V1)?
val myList = List(12, 34, "ABC")
Version 1
for { i <- (0 to 3).toList } yield myList.lift(i)
// res1: List[Option[Any]] = List(Some(12), Some(34), Some(ABC), None)
Version 2
for {
i <- (0 to 3).toList
x <- myList.lift(i)
} yield x
// res2: List[Any] = List(12, 34, ABC)
Desugaring the first case:
// desugar for comprehension:
(0 to 3).toList.map(
i => myList.lift(i))
Desugaring the second case:
// desugar for comprehension:
(0 to 3).toList.flatMap(
i => myList.lift(i).map(
x => x))
// remove .map(x => x):
(0 to 3).toList.flatMap(
i => myList.lift(i))
// desugar flatMap:
(0 to 3).toList.map(
i => myList.lift(i)).flatten
The second case simplifies to the first case with a .flatten at the end, which explains the difference in the results: res2 = res1.flatten.
What's actually going on?
Scala can treat Option as a sequence:
Some(foo) --> Seq(foo)
None --> Seq()
The .flatten is just flattening the sequence of sequences.
If you're curious about the types:
scala.collection.Seq.flatten requires that the 'inner' type have an implicit conversion to GenTraversableOnce[T]
there's a global implicit conversion from Option[T] to Iterable[T]
Iterable[T] <: GenTraversableOnce[T]
What does <- mean then?
The <- in x <- myList.lift(i) doesn"t just assign a variable to a value, it "gets a value out of" myList.lift(i). When you "get a value out of" an Option[T], you get foo for Some(foo) and nothing for None. "Getting nothing" means the yield doesn"t run at all for a None, so nothing shows up in the result for the "iteration" when i = 3.
If you're curious about this "get a value out of" concept that is defined for Seq, Option, and many other types in Scala, it is defined for any Monad.
If you de-sugar the for comprehensions
Version 1
List(0, 1, 2, 3).map({ i =>
myList.lift(i)
})
Version 2
List(0, 1, 2, 3).flatMap({ i =>
myList.lift(i).map({ x => x })
})
what is the reason the yield output in V2 no longer respects the data type returned by myList.lift()
The yield does nothing to the output of List.lift:
myList.lift(i) returns Option[Any]
myList.lift(i).map({ x => x }) returns Option[Any]
It's the flatMap that flattens the Option[Any] to Any (by discarding None and un-wrapping Some(a: Any) => a)

Is there a native grouping function that works like the sortWith function?

There are a few libraries such as Spark and other Scala extensions that have the "groupWith" function available. This function allows you to compare an element to the rest of the collection and then group it using one or more predicates. There doesn't seem to be any native functionality in Scala for this but they do have the sortWith function that behaves similarly but only sorts the items instead of grouping them. If the explanation isn't sufficient here's a small code sample that should display what I'm trying to do:
val list = List(1,2,3,4,5,5)
val groupedList = list.groupWith{ (e,c) =>
e == c
}
This is a very simple example and I want to do more complicated comparisons such as
e + 1 == c
So again the question is are there any native Scala functions that do this? Any suggestions or workarounds?
Update:
From the simple examples given it seems it's not exactly clear what I'm trying to do, here's a better example:
Say I have a case class and a list of these objects:
case class Item(num: Int, color: String)
val list = List(new Item(13, "red"), new Item(14,"red"), new Item(15, "blue"), new Item(16, "red"))
list.groupWith{ (e,c) =>
(e.num -1 == c.num || e.num + 1 == c.num ) && e.color == c.color
}
And this should return something like this:
res8: List[List[Item]] = List(List(Item(13,red), Item(14,red)), List(Item(15,blue)), List(Item(16,red)))
Here's an implementation:
// Takes the list as a parameter, can use pimp-my-library if you want
def groupWith[A](xs: List[A], f: (A, A) => Boolean) = {
// helper function to add "e" to any list with a member that matches the predicate
// otherwise add it to a list of its own
def addtoGroup(gs: List[List[A]], e: A): List[List[A]] = {
val (before, after) = gs.span(_.exists(!f(_, e)))
if (after.isEmpty)
List(e) :: gs
else
before ::: (e :: after.head) :: after.tail
}
// now a simple foldLeft adding each element to the appropriate list
xs.foldLeft(Nil: List[List[A]])(addtoGroup)
}
groupWith(list, { (e: Item, c: Item) =>
(e.num - 1 == c.num || e.num + 1 == c.num) && e.color == c.color})
//| res0: List[List[groups.groups.Item]] =
// List(List(Item(16,red)),
// List(Item(15 ,blue)),
// List(Item(14,red), Item(13,red)))
Not sure if this what you want (check my comments to your question), but there is method groupBy defined in GenTraversableLike which List inherits (not only List). You will get:
scala> val list = List(1,2,3,4,5,5)
list: List[Int] = List(1, 2, 3, 4, 5, 5)
scala> list.groupBy( el => el )
res0: scala.collection.immutable.Map[Int,List[Int]] = Map(5 -> List(5, 5), 1 -> List(1), 2 -> List(2), 3 -> List(3), 4 -> List(4))
scala> list.groupBy( el => el + 1 )
res1: scala.collection.immutable.Map[Int,List[Int]] = Map(5 -> List(4), 6 -> List(5, 5), 2 -> List(1), 3 -> List(2), 4 -> List(3))
Basically you need to provide discriminator function from value to key and you will get Map[Key, List[Value].
Is this what you want?

Split a collection to those items that satisfy a predicate, and those that don't [duplicate]

How do I split a sequence into two lists by a predicate?
Alternative: I can use filter and filterNot, or write my own method, but isn't there a better more general (built-in) method ?
By using partition method:
scala> List(1,2,3,4).partition(x => x % 2 == 0)
res0: (List[Int], List[Int]) = (List(2, 4),List(1, 3))
Good that partition was the thing you wanted -- there's another method that also uses a predicate to split a list in two: span.
The first one, partition will put all "true" elements in one list, and the others in the second list.
span will put all elements in one list until an element is "false" (in terms of the predicate). From that point forward, it will put the elements in the second list.
scala> Seq(1,2,3,4).span(x => x % 2 == 0)
res0: (Seq[Int], Seq[Int]) = (List(),List(1, 2, 3, 4))
You might want to take a look at scalex.org - it allows you to search the scala standard library for functions by their signature. For example, type the following:
List[A] => (A => Boolean) => (List[A], List[A])
You would see partition.
You can also use foldLeft if you need something a little extra. I just wrote some code like this when partition didn't cut it:
val list:List[Person] = /* get your list */
val (students,teachers) =
list.foldLeft(List.empty[Student],List.empty[Teacher]) {
case ((acc1, acc2), p) => p match {
case s:Student => (s :: acc1, acc2)
case t:Teacher => (acc1, t :: acc2)
}
}
I know I might be late for the party and there are more specific answers, but you could make good use of groupBy
val ret = List(1,2,3,4).groupBy(x => x % 2 == 0)
ret: scala.collection.immutable.Map[Boolean,List[Int]] = Map(false -> List(1, 3), true -> List(2, 4))
ret(true)
res3: List[Int] = List(2, 4)
ret(false)
res4: List[Int] = List(1, 3)
This makes your code a bit more future-proof if you need to change the condition into something non boolean.
If you want to split a list into more than 2 pieces, and ignore the bounds, you could use something like this (modify if you need to search for ints)
def split(list_in: List[String], search: String): List[List[String]] = {
def split_helper(accum: List[List[String]], list_in2: List[String], search: String): List[List[String]] = {
val (h1, h2) = list_in2.span({x: String => x!= search})
val new_accum = accum :+ h1
if (h2.contains(search)) {
return split_helper(new_accum, h2.drop(1), search)
}
else {
return accum
}
}
return split_helper(List(), list_in, search)
}
// TEST
// split(List("a", "b", "c", "d", "c", "a"), {x: String => x != "x"})

Flatten Scala Try

Is there a simple way to flatten a collection of try's to give either a success of the try values, or just the failure?
For example:
def map(l:List[Int]) = l map {
case 4 => Failure(new Exception("failed"))
case i => Success(i)
}
val l1 = List(1,2,3,4,5,6)
val result1 = something(map(l1))
result1: Failure(Exception("failed"))
val l2 = List(1,2,3,5,6)
val result2 = something(map(l2))
result2: Try(List(1,2,3,5,6))
And can how would you handle multiple Failures in the collection?
This is pretty close to minimal for fail-first operation:
def something[A](xs: Seq[Try[A]]) =
Try(xs.map(_.get))
(to the point where you shouldn't bother creating a method; just use Try). If you want all the failures, a method is reasonable; I'd use an Either:
def something[A](xs: Seq[Try[A]]) =
Try(Right(xs.map(_.get))).
getOrElse(Left(xs.collect{ case Failure(t) => t }))
A little less verbose, and more type safe:
def sequence[T](xs : Seq[Try[T]]) : Try[Seq[T]] = (Try(Seq[T]()) /: xs) {
(a, b) => a flatMap (c => b map (d => c :+ d))
}
Results:
sequence(l1)
res8: scala.util.Try[Seq[Int]] = Failure(java.lang.Exception: failed)
sequence(l2)
res9: scala.util.Try[Seq[Int]] = Success(List(1, 2, 3, 5, 6))
Maybe not as simple as you hoped for, but this works:
def flatten[T](xs: Seq[Try[T]]): Try[Seq[T]] = {
val (ss: Seq[Success[T]]#unchecked, fs: Seq[Failure[T]]#unchecked) =
xs.partition(_.isSuccess)
if (fs.isEmpty) Success(ss map (_.get))
else Failure[Seq[T]](fs(0).exception) // Only keep the first failure
}
val xs = List(1,2,3,4,5,6)
val ys = List(1,2,3,5,6)
println(flatten(map(xs))) // Failure(java.lang.Exception: failed)
println(flatten(map(ys))) // Success(List(1, 2, 3, 5, 6))
Note that the use of partition is not as type safe as it gets, as witnessed by the #unchecked annotations. In that respect, a foldLeft that accumulates two sequences Seq[Success[T]] and Seq[Failure[T]] would be better.
If you wanted to keep all failures, you can use this:
def flatten2[T](xs: Seq[Try[T]]): Either[Seq[T], Seq[Throwable]] = {
val (ss: Seq[Success[T]]#unchecked, fs: Seq[Failure[T]]#unchecked) =
xs.partition(_.isSuccess)
if (fs.isEmpty) Left(ss map (_.get))
else Right(fs map (_.exception))
}
val zs = List(1,4,2,3,4,5,6)
println(flatten2(map(xs))) // Right(List(java.lang.Exception: failed))
println(flatten2(map(ys))) // Left(List(1, 2, 3, 5, 6))
println(flatten2(map(zs))) // Right(List(java.lang.Exception: failed,
// java.lang.Exception: failed))
As an addition to Impredicative's answer and comment, if you have both scalaz-seven and scalaz-contrib/scala210 in your dependencies:
> scala210/console
[warn] Credentials file /home/folone/.ivy2/.credentials does not exist
[info] Starting scala interpreter...
[info]
Welcome to Scala version 2.10.0 (OpenJDK 64-Bit Server VM, Java 1.7.0_17).
Type in expressions to have them evaluated.
Type :help for more information.
scala> import scala.util._
import scala.util._
scala> def map(l:List[Int]): List[Try[Int]] = l map {
| case 4 => Failure(new Exception("failed"))
| case i => Success(i)
| }
map: (l: List[Int])List[scala.util.Try[Int]]
scala> import scalaz._, Scalaz._
import scalaz._
import Scalaz._
scala> import scalaz.contrib.std.utilTry._
import scalaz.contrib.std.utilTry._
scala> val l1 = List(1,2,3,4,5,6)
l1: List[Int] = List(1, 2, 3, 4, 5, 6)
scala> map(l1).sequence
res2: scala.util.Try[List[Int]] = Failure(java.lang.Exception: failed)
scala> val l2 = List(1,2,3,5,6)
l2: List[Int] = List(1, 2, 3, 5, 6)
scala> map(l2).sequence
res3: scala.util.Try[List[Int]] = Success(List(1, 2, 3, 5, 6))
You need scalaz to get an Applicative instance for the List (hidden in the MonadPlus instance), to get the sequence method. You need scalaz-contrib for the Traverse instance of Try, which is required by the sequence's type signature.
Try lives outside of scalaz, since it only appeared in scala 2.10, and scalaz aims to cross-compile to earlier versions).
Starting in Scala 2.13, most collections are provided with a partitionMap method which partitions elements based on a function returning either Right or Left.
In our case we can call partitionMap with a function that transforms our Trys into Eithers (Try::toEither) in order to partition Successes as Rights and Failures as Lefts.
Then it's just a matter of matching the resulting partitioned tuple of lefts and rights based on whether or not there are lefts:
tries.partitionMap(_.toEither) match {
case (Nil, rights) => Success(rights)
case (firstLeft :: _, _) => Failure(firstLeft)
}
// * val tries = List(Success(10), Success(20), Success(30))
// => Try[List[Int]] = Success(List(10, 20, 30))
// * val tries = List(Success(10), Success(20), Failure(new Exception("error1")))
// => Try[List[Int]] = Failure(java.lang.Exception: error1)
Details of the intermediate partitionMap step:
List(Success(10), Success(20), Failure(new Exception("error1"))).partitionMap(_.toEither)
// => (List[Throwable], List[Int]) = (List(java.lang.Exception: error1), List(10, 20))
Have a look on the liftweb Box monad. With the help of the tryo constructor function, it gives you exactly the abstraction you are looking for.
With tryo you can lift a function into a Box. The box then either contains the result from the function or it contains an error. You can then access the box with the usual monadic helper functions (flatMap, filter, etc.), without bothering if the box contains an error or the result form the function.
Example:
import net.liftweb.util.Helpers.tryo
List("1", "2", "not_a_number") map (x => tryo(x.toInt)) map (_ map (_ + 1 ))
Results to
List[net.liftweb.common.Box[Int]] =
List(
Full(2),
Full(3),
Failure(For input string: "not_a_number",Full(java.lang.NumberFormatException: For input string: "not_a_number"),Empty)
)
You can skip the erroneous values with flatMap
List("1", "2", "not_a_number") map (x => tryo(x.toInt)) flatMap (_ map (_ + 1 ))
Results
List[Int] = List(2, 3)
There are multiple other helper methods, e.g. for combining boxes (while chaining error messages). You can find a good overview here: Box Cheat Sheet for Lift
You can use it on its own, no need to use the whole lift framework. For the examples above I used the follwing sbt script:
scalaVersion := "2.9.1"
libraryDependencies += "net.liftweb" %% "lift-common" % "2.5-RC2"
libraryDependencies += "net.liftweb" %% "lift-util" % "2.5-RC2"
These are my 2cents:
def sequence[A, M[_] <: TraversableOnce[_]](in: M[Try[A]])
(implicit cbf:CanBuildFrom[M[Try[A]], A, M[A]]): Try[M[A]] = {
in.foldLeft(Try(cbf(in))) {
(txs, tx) =>
for {
xs <- txs
x <- tx.asInstanceOf[Try[A]]
} yield {
xs += x
}
}.map(_.result())
}

How to split a sequence into two pieces by predicate?

How do I split a sequence into two lists by a predicate?
Alternative: I can use filter and filterNot, or write my own method, but isn't there a better more general (built-in) method ?
By using partition method:
scala> List(1,2,3,4).partition(x => x % 2 == 0)
res0: (List[Int], List[Int]) = (List(2, 4),List(1, 3))
Good that partition was the thing you wanted -- there's another method that also uses a predicate to split a list in two: span.
The first one, partition will put all "true" elements in one list, and the others in the second list.
span will put all elements in one list until an element is "false" (in terms of the predicate). From that point forward, it will put the elements in the second list.
scala> Seq(1,2,3,4).span(x => x % 2 == 0)
res0: (Seq[Int], Seq[Int]) = (List(),List(1, 2, 3, 4))
You might want to take a look at scalex.org - it allows you to search the scala standard library for functions by their signature. For example, type the following:
List[A] => (A => Boolean) => (List[A], List[A])
You would see partition.
You can also use foldLeft if you need something a little extra. I just wrote some code like this when partition didn't cut it:
val list:List[Person] = /* get your list */
val (students,teachers) =
list.foldLeft(List.empty[Student],List.empty[Teacher]) {
case ((acc1, acc2), p) => p match {
case s:Student => (s :: acc1, acc2)
case t:Teacher => (acc1, t :: acc2)
}
}
I know I might be late for the party and there are more specific answers, but you could make good use of groupBy
val ret = List(1,2,3,4).groupBy(x => x % 2 == 0)
ret: scala.collection.immutable.Map[Boolean,List[Int]] = Map(false -> List(1, 3), true -> List(2, 4))
ret(true)
res3: List[Int] = List(2, 4)
ret(false)
res4: List[Int] = List(1, 3)
This makes your code a bit more future-proof if you need to change the condition into something non boolean.
If you want to split a list into more than 2 pieces, and ignore the bounds, you could use something like this (modify if you need to search for ints)
def split(list_in: List[String], search: String): List[List[String]] = {
def split_helper(accum: List[List[String]], list_in2: List[String], search: String): List[List[String]] = {
val (h1, h2) = list_in2.span({x: String => x!= search})
val new_accum = accum :+ h1
if (h2.contains(search)) {
return split_helper(new_accum, h2.drop(1), search)
}
else {
return accum
}
}
return split_helper(List(), list_in, search)
}
// TEST
// split(List("a", "b", "c", "d", "c", "a"), {x: String => x != "x"})