I have looked at these links
http://blog.danielwellman.com/2008/03/using-scalas-op.html
http://blog.tmorris.net/scalaoption-cheat-sheet/
I have a map of [String, Integer] and when I do a map.get("X") I get an option. I would like the following.
val Int count = map.get(key);
// If the key is there I would like value if it is not I want 0
How do I achieve this in one line? I need to do this several times. It looks a bit inefficient to write a function everytime for doing this. I am sure there is some intelligent one line quirk that I am missing but I really like to get the value into an integer in ONE line :)
Just use getOrElse method:
val count: Int = map.getOrElse(key,0);
Note also, that in Scala you write type after name, not before.
#om-nom-nom (classic screen name) has the correct answer, but in the interest of providing yet another way™
val count = map.get(key) fold(0)(num => num)
Before in-the-know users bash me with, "Option has no fold!", fold has been added to Option in Scala 2.10
getOrElse is of course better in the current case, but in some Some/None scenarios it may be interesting to 1-liner with fold like so (edited complements of #Debiliski who tested against latest 2.10 snapshot):
val count = map.get(k).fold(0)(dao.userlog.count(_))
I suppose in 2.9.2 and under we can already do:
val count = map get(k) map ( dao.userlog.count(_) ) getOrElse(0)
Which is to say, in Scala there is often more than one way to do the same thing: in the linked thread, the OP shows more than 10 alternative means to achieve Option fold ;-)
Yet another way.
import scalaz._, Scalaz._
scala> val m = Map(9 -> 33)
m: scala.collection.immutable.Map[Int,Int] = Map(9 -> 33)
scala> m.get(9).orZero
res3: Int = 33
scala> m.get(8).orZero
res4: Int = 0
Related
I am new to scala, please help me with the below question.
Can we call map method on an Option? (e.g. Option[Int].map()?).
If yes then could you help me with an example?
Here's a simple example:
val x = Option(5)
val y = x.map(_ + 10)
println(y)
This will result in Some(15).
If x were None instead, y would also be None.
Yes:
val someInt = Some (2)
val noneInt:Option[Int] = None
val someIntRes = someInt.map (_ * 2) //Some (4)
val noneIntRes = noneInt.map (_ * 2) //None
See docs
You can view an option as a collection that contains exactly 0 or 1 items. Mapp over the collection gives you a container with the same number of items, with the result of applying the mapping function to every item in the original.
Sometimes it's more convenient to use fold instead of mapping Options. Consider the example:
scala> def printSome(some: Option[String]) = some.fold(println("Nothing provided"))(println)
printSome: (some: Option[String])Unit
scala> printSome(Some("Hi there!"))
Hi there!
scala> printSome(None)
Nothing provided
You can easily proceed with the real value inside fold, e.g. map it or do whatever you want, and you're safe with the default fold option which is triggered on Option#isEmpty.
I recently discovered breakOut and love how elegant it is, but noticed that it doesn't maintain order.
eg (from REPL):
scala> val list = List("apples", "bananas", "oranges")
list: List[String] = List(apples, bananas, oranges)
scala> val hs: HashMap[String, Int] = list.map{x => (x -> x.length)}(breakOut)
hs: scala.collection.mutable.HashMap[String,Int] = Map(bananas -> 7, oranges -> 7, apples -> 6)
I like using breakOut since it's really clean and neat but ordering does matter to me. Is there a way to get it to maintain order or do I have to add elements to my hashmap one at a time?
You see this behavior, because of the fact that HashMap is a data structure with undefined order. Even if you see some ordering of the elements in the hash map and it's consistent across the runs, you shouldn't depend on it. If you really need the order, consider using LinkedHashMap
For example, my input is:
scala> val myList = List("7842", "abf45", "abd", "56")
myList: List[String] = List(7842, abf45, abd, 56)
7842 and 56 can be converted to Int; therefore, my expected output is 2. We can assume that negative integers don't happen, so -67 is not possible.
This is what I have so far:
scala> myList.map(x => Try(x.toInt).getOrElse(-1)).count(_ > -1)
res15: Int = 2
This should work correctly, but I feel like I am missing a more elegant and readable solution, because all I have to do is count number of successes.
I would caution against using exception handling (like Try) in control flow -- it's very slow.
Here's a solution that uses idiomatic Scala collection operations, performs well, and will not count negative numbers:
scala> val myList = List("7842", "abf45", "abd", "56")
myList: List[String] = List(7842, abf45, abd, 56)
scala> myList.count(_.forall(_.isDigit))
res8: Int = 2
EDIT: #immibis pointed out that this won't detect strings of numbers that exceed Integer.MaxValue. If this is a concern, I would recommend one of the following approaches:
import scala.util.Try
myList.count(x => Try(x.toInt).filter(_ >= 0).isSuccess)
or, if you want to keep the performance of my first answer while still handling this edge case:
import scala.util.Try
myList.count(x => x.forall(_.isDigit) && Try(x.toInt).filter(_ >= 0).isSuccess)
This is a bit shorter:
myList.count(x => Try(x.toInt).isSuccess)
Note that this solution will handle any string that can be converted to integer via .toInt, including negative numbers.
You may consider string.matches method with regex as well, to match only positive integers:
val myList = List("7842", "abf45", "abd", "-56")
// myList: List[String] = List(7842, abf45, abd, -56)
myList.count(_.matches("\\d+"))
// res18: Int = 1
If negative integers need to be counted (and take into account possible +/- signs):
myList.count(_.matches("[+-]?\\d+"))
// res17: Int = 2
Starting Scala 2.13 and the introduction of String::toIntOption, we can count items ("34"/"2s3") for which applying toIntOption (Some(34)/None) is defined (true/false):
List("34", "abf45", "2s3", "56").count(_.toIntOption.isDefined) // 2
Often I find myself passing a Seq with just one element to methods like this:
def myMethod(myList: Seq[Int]) = { ... }
Usually I do this like so:
myMethod(List(42))
But it occurs to me that this might not be the most elegant way, and if there's one thing about Scala that I love, it is its capability of blowing my mind by cutting down on characters used when I thought it impossible.
So, is there a shorter or more elegant representation of a single-item Seq than List(42)?
I can think of a couple worse options!
42 to 42
42 :: List()
Probably the shortest built-in way is to just use Seq companion object's apply and write
myMethod(Seq(42))
That apply function returns the default Seq implementation, that is A List and is therefore equivalent to using List(42).
I'm not sure there's any Seq implementation with a shorter name, but you can surely implement your own or simply import Seq (or List) while aliasing the name:
scala> import scala.collection.{Seq => S}
scala> S(42)
res0: Seq[Int] = List(3)
A shorter usage syntax may be obtained with this implicit,
implicit def SingletonSeq(i: Int) = Seq(i)
Hence
def myMethod(myList: Seq[Int]) = myList.size
myMethod(42)
res: 1
Suppose I have an iterator:
val it = List("a","b","c").iterator
I want a copy of it; my code is:
val it2 = it.toList.iterator
It's correct, but seems not good. Is there any other API to do it?
The method you are looking for is duplicate.
scala> val it = List("a","b","c").iterator
it: Iterator[java.lang.String] = non-empty iterator
scala> val (it1,it2) = it.duplicate
it1: Iterator[java.lang.String] = non-empty iterator
it2: Iterator[java.lang.String] = non-empty iterator
scala> it1.length
res11: Int = 3
scala> it2.mkString
res12: String = abc
Warning: as of Scala 2.9.0, at least, this leaves the original iterator empty. You can val ls = it.toList; val it1 = ls.iterator; val it2 = ls.iterator to get two copies. Or use duplicate (which works for non-lists also).
Rex's answer is by the book, but in fact your original solution is by far the most efficient for scala.collection.immutable.List's.
List iterators can be duplicated using that mechanism with essentially no overhead. This can be confirmed by a quick review of the implementation of iterator() in scala.collection.immutable.LinearSeq, esp. the definition of the toList method, which simply returns the _.toList of the backing Seq which, if it's a List (as it is in your case) is the identity.
I wasn't aware of this property of List iterators before investigating your question, and I'm very grateful for the information ... amongst other things it means that many "list pebbling" algorithms can be implemented efficiently over Scala immutable Lists using Iterators as the pebbles.