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
Related
I have a composition of combinators in Scala, and the last one is .top, which I could use as .top(num)(Ordering[(Int, Int)].reverse) depending on a boolean parameter.
How do I implement this composition of combinators to use or not use .reverse depending on the boolean parameter, in the same line? I mean, without creating another val to indicate whether .reverse is used?
val mostPopularHero = sparkContext
.textFile("resource/marvel/Marvel-graph.txt") // build up superhero co-apperance data
.map(countCoOccurrences) // convert to (hero ID, number of connections) RDD
.reduceByKey((x, y) => x + y) // combine entries that span more than one line
.map(x => (x._2, x._1)) // flip it from (hero ID, number of connections) to (number of connections, hero ID)
.top(num)(Ordering[(Int, Int)].reverse)
Solution 0
As nicodp has already pointed out, if you have a boolean variable b in scope, you can simply replace the expression
Ordering[(Int, Int)]
by an if-expression
if (b) Ordering[(Int, Int)] else Ordering[(Int, Int)].reverse
I have to admit that this is the shortest and clearest solution I could come up with.
However... I didn't quite like that the expression Ordering[(Int, Int)] appears in the code twice. It doesn't really matter in this case, because it's short, but what if the expression were a bit longer? Apparently, even Ruby has something for such cases.
So, I tried to come up with some ways to not repeat the subexpression Ordering[(Int, Int)]. The nicest solution would be if we had a default Id-monad implementation in the standard library, because then we could simply wrap the one value in pure, and then map it using the boolean.
But there is no Id in standard library. So, here are a few other proposals, just for the case that the expression in question becomes longer:
Solution 1
You can use blocks as expressions in scala, so you can replace the above
Ordering[(Int, Int)] by:
{val x = Ordering[(Int, Int)]; if (b) x else x.reverse}
Update: Wait! This is shorter than the version with repetition! ;)
Solution 2
Define the function that conditionally reverses an ordering, declare Ordering[(Int, Int)] as the type of the argument, and then
instead of re-typing Ordering[(Int, Int)] as an expression, use implicitly:
((x: Ordering[(Int, Int)]) => if (b) x else x.reverse)(implicitly)
Solution 3
We don't have Id, but we can abuse constructors and eliminators of other functors. For example, one could wrap the complex expression in a List or Option, then map it, then unpack the result. Here is a variant with Some:
Some(Ordering[(Int, Int)]).map{ x => if(b) x else x.reverse }.get
Ideally, this would have been Id instead of Some. Notice that Solution 1 does something similar with the default ambient monad.
Solution 4
Finally, if the above pattern occurs more than once in your code, it might be worth it to introduce some extra syntax to deal with it:
implicit class ReversableOrderingOps[X](ord: Ordering[X]) {
def reversedIf(b: Boolean): Ordering[X] = if (b) ord.reverse else ord
}
Now you can define orderings like this:
val myConditionHolds = true
val myOrd = Ordering[(Int, Int)] reversedIf myConditionHolds
or use it in your lengthy expression directly:
val mostPopularHero = sparkContext
.textFile("resource/marvel/Marvel-graph.txt")
.map(countCoOccurrences)
.reduceByKey((x, y) => x + y)
.map(x => (x._2, x._1))
.top(num)(Ordering[(Int, Int)] reversedIf myConditionHolds)
I'm not quite sure if you have access to the boolean parameter here or not, but you can work this out as follows:
.top(num)(if (booleanParameter) Ordering[(Int, Int)].reverse else Ordering[(Int, Int)])
I have an emptyListBuffer[ListBuffer[(String, Int)]]() initialized like so, and given a number n, I want to fill it with n ListBuffer[(String, Int)].
For example, if n=2 then I can initialize two ListBuffer[(String, Int)] within ListBuffer[ListBuffer[(String, Int)]]() if that makes any sense. I was trying to loop n times and use the insertAll function to insert an empty list but I didn't work.
use fill
fill is a standard Scala library function in order to fill a data structure with predefined elements. Its quite handy and save lot of typing.
ListBuffer.fill(100)(ListBuffer("Scala" -> 1))
Scala REPL
scala> import scala.collection.mutable._
import scala.collection.mutable._
scala> ListBuffer.fill(100)(ListBuffer("Scala" -> 1))
res4: scala.collection.mutable.ListBuffer[scala.collection.mutable.ListBuffer[(String, Int)]] = ListBuffer(ListBuffer((Scala,1)), ListBuffer((Scala,1)), ListBuffer((Scala,1)), ListBuffer((Scala,1)), ListBuffer((Scala,1)) ...
fill implementation in Standard library
def fill[A](n: Int)(elem: => A): CC[A] = {
val b = newBuilder[A]
b.sizeHint(n)
var i = 0
while (i < n) {
b += elem
i += 1
}
b.result()
}
The above implementation is for one dimensional data structure.
General suggestions
Looks like you are using Scala like the Java way. This is not good. Embrace functional way for doing things for obvious benefits.
Use immutable collections like List, Vector instead of mutable collections. Do not use mutable collections until and unless you have string reason for it.
Same thing can be done using immutable List
List.fill(100)(List("scala" -> 1))
scala -> 1 is same as ("scala", 1)
I have a list of Integers and I want to make a String of it.
var xs = list(1,2,3,4,5)
(xs foldLeft "") (_+_) // String = 12345
with foldLeft it works perfect, but my question is does it also work with reduceLeft? And if yes, how?
It cannot work this way with reduceLeft. Informally you can view reduceLeft as a special case of foldLeft where the accumulated value is of the same type as the collection's elements. Because in your case the element type is Int and the accumulated value is String, there is no way to use reduceLeft in the way you used foldLeft.
However in this specific case you can simply convert all your Int elements to String up front, and then reduce:
scala> xs.map(_.toString) reduceLeft(_+_)
res5: String = 12345
Note that this will throw an exception if the list is empty. This is another difference with foldLeft, which handles the empty case just fine (because it has an explicit starting value).
This is also less efficient because we create a whole new collection (of strings) just to reduce it on the spot.
All in all, foldLeft is a much better choice here.
It takes a little bit of work to make sure the types are understood correctly. Expanding them, though, you could use something like:
(xs reduceLeft ((a: Any, b: Int) => a + b.toString)).toString
I am planning to start using Monadic style in my Scala code for, amongst others, threading state. Here's a simplified example of combining 3 monadic functions (and caring only about the side effects)
import scalaz._
import Scalaz._
object MonadTest {
def adder(i: Int) = State[String, Int] ({str: String => (str + i.toString + " ", i) })
val oneTwoThreeMonad = for {
m1 <- adder(1)
m2 <- adder(2)
m3 <- adder(3)
} yield m3
oneTwoThreeMonad("start: ")._1 //String = "start: 1 2 3 "
}
This all is pretty self-explanatory and works as expected. But for this approach to be really useful to me I would like to be able to combine it with List for-comprehension. Here's a bit of (not working) code to show what I mean:
val list = List(1, 2, 3)
val oneTwoThreeBis = for {
i <- list
mx <- adder(i)
} yield mx
Basically I would like to be able to combine monads based on arguments from a List - run the monadic function on each of the elements of the list and accumulate the side-effects as I go. I understand the example syntax doesn't work and I see why it doesn't - I'm just looking for a clean, elegant equivalent.
I am pretty sure it is possible to achieve this using scalaz monad transformers, more specifically with StateT but I'm not really sure how one would go about doing it.
PS. I'm using Scalaz 7.0-M3, so the syntax might be a little different from the most common 6.x.
I'm not sure I understand exactly what you're looking for, but it sounds like you want something more like traverse here (where traverse is a more general version of Haskell's mapM):
import scalaz._, Scalaz._
def adder(i: Int) = State[String, Int](str => (str + i.toString + " ", i))
List(1, 2, 3).traverseS(adder)("start: ")._1
This will print the following, as expected:
res0: String = "start: 1 2 3 "
Note that I'm using traverseS (where the S stands for State) to avoid having to write out the rather messy type parameter, but traverse is more generally useful anytime you want to map a monadic function over something traversable.
I'm happy to give a StateT example if this isn't what you wanted, but that's going to end up with you having something of type List[(String, Int)].
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