I am trying to get the hang of the flatMap implementation in Scala. Based on the definition in Scala programming
Function returning a list of elements as its right argument. It applies the function to each list and returns the concatenation of all function results.
Now to understand this, I have following implementations
val listwords = List(List("abc"),List("def"),List("ghi"))
val res2 = listwords flatMap (_+"1")
println(res2) //output- List(L, i, s, t, (, a, b, c, ), 1, L, i, s, t, (, d, e, f, ), 1, L, i, s, t, (, g, h, i, ), 1)
val res3 = listwords flatMap (_.apply(0).toCharArray())
println(res3) //output- List(a, b, c, d, e, f, g, h, i)
Looking at first output which drives me crazy, why is List[List[String]] treated like List[String]?
After all with answer for above question, someone please help me to perform an operation which needs to pick the first character of the first string of each inner and result in a List[Char]. So given the listwords, I want the output to be List('a', 'd', 'g').
List("abc") + "1" is equivalent to List("abc").toString + "1" so it returns the string "List(a, b, c)1". The type of List.flatMap is
flatMap[B](f: (A) ⇒ GenTraversableOnce[B]): List[B]
and your function has type (List[String] => String). String extends GenTraversableOnce[Char] so your result list has type List[Char].
The code listwords flatMap (_+"1") can be rewritten as listwords flatMap (list => list.toString + "1"). So you basically transformed all lists to strings using toString method.
To obtain first characters you can use the following expression:
listwords.flatMap(_.headOption).flatMap(_.headOption)
First of all, you need to understand the difference between the map and the flatMap methods. Both of them iterate over some container and apply a function literal to every element. The difference is that the flatMap is making one more additional operation: it flattens the structure of the container. There is also a method that allows you just to do the flattening and its called flatten (so the flatMap is the equivalent of the map operation followed by the flatten operation). The second thing you have to remember is that you're modifying (mapping over) nested lists, so you need to nest your map/flatMap calls as well. Those examples should clarify all of those things to you:
scala> val wordLists = List(List("abc"),List("de"),List("f"), List())
wordLists: List[List[String]] = List(List(abc), List(de), List(f), List())
scala> val words = wordsLists.flatten
words: List[String] = List(abc, de, f)
scala> val replacedWordLists = wordsLists.map(_ => List("xyz"))
replacedWordLists: List[List[String]] = List(List(xyz), List(xyz), List(xyz), List(xyz))
scala> val replacedWords = wordsLists.map(_ => List("xyz")).flatten // Equivalent: wordsLists.flatMap(_ => List("xyz"))
replacedWords: List[String] = List(xyz, xyz, xyz, xyz)
scala> val upperCaseWordLists = wordsLists.map(_.map(_.toUpperCase))
upperCaseWordLists: List[List[String]] = List(List(ABC), List(DE), List(F), List())
scala> val upperCaseWords = wordsLists.map(_.map(_.toUpperCase)).flatten // Equivalent: wordsLists.flatMap(_.map(_.toUpperCase))
upperCaseWords: List[String] = List(ABC, DE, F)
scala> val optionalFirstLetterLists = wordLists.map(_.map(_.headOption))
optionalFirstLetterLists: List[List[Option[Char]]] = List(List(Some(a)), List(Some(d)), List(Some(f)), List())
scala> val optionalFirstLetters = wordLists.map(_.map(_.headOption)).flatten // Equivalent: wordLists.flatMap(_.map(_.headOption))
optionalFirstLetters: List[Option[Char]] = List(Some(a), Some(d), Some(f))
scala> val firstLetterLists = wordLists.map(_.map(_.headOption).flatten) // Equivalent: wordLists.map(_.flatMap(_.headOption))
firstLetterLists: List[List[Char]] = List(List(a), List(d), List(f), List())
scala> val firstLetters = wordLists.map(_.flatMap(_.headOption)).flatten // Equivalent: wordLists.flatMap(_.flatMap(_.headOption))
firstLetters: List[Char] = List(a, d, f)
_+"1" isn't doing what you think it's doing.
It's interpreted as list: List[String] => list.+("1")
Since List[String] doesn't contain such a method, the compiler looks for an implicit conversion in scope. It finds any2stringadd. (See http://docs.scala-lang.org/tutorials/tour/implicit-conversions for more on implicit conversions)
implicit final class any2stringadd[A](private val self: A) extends AnyVal {
def +(other: String): String = String.valueOf(self) + other
}
list: List[String] => list.+("1")
now turns into
list: List[String] => new any2stringadd(list).+("1")
which returns String.valueOf(list) + "1"
Related
I have a function in a context, (in a Maybe / Option) and I want to pass it a value and get back the return value, directly out of the context.
Let's take an example in Scala :
scala> Some((x:Int) => x * x)
res0: Some[Int => Int] = Some(<function1>)
Of course, I can do
res0.map(_(5))
to execute the function, but the result is wrapped in the context.
Ok, I could do :
res0.map(_(5)).getOrElse(...)
but I'm copy/pasting this everywhere in my code (I have a lot of functions wrapped in Option, or worst, in Either...).
I need a better form, something like :
res0.applyOrElse(5, ...)
Does this concept of 'applying a function in a concept to a value and immediatly returning the result out of the context' exists in FP with a specific name (I'm lost in all those Functor, Monad and Applicatives...) ?
You can use andThen to move the default from the place where you call the function to the place where you define it:
val foo: String => Option[Int] = s => Some(s.size)
val bar: String => Int = foo.andThen(_.getOrElse(100))
This only works for Function1, but if you want a more generic version, Scalaz provides functor instances for FunctionN:
import scalaz._, Scalaz._
val foo: (String, Int) => Option[Int] = (s, i) => Some(s.size + i)
val bar: (String, Int) => Int = foo.map(_.getOrElse(100))
This also works for Function1—just replace andThen above with map.
More generally, as I mention above, this looks a little like unliftId on Kleisli, which takes a wrapped function A => F[B] and collapses the F using a comonad instance for F. If you wanted something that worked generically for Option, Either[E, ?], etc., you could write something similar that would take a Optional instance for F and a default value.
You could write something like applyOrElse using Option.fold.
fold[B](ifEmpty: ⇒ B)(f: (A) ⇒ B): B
val squared = Some((x:Int) => x * x)
squared.fold {
// or else = ifEmpty
math.pow(5, 2).toInt
}{
// execute function
_(5)
}
Using Travis Browns recent answer on another question, I was able to puzzle together the following applyOrElse function. It depends on Shapeless and you need to pass the arguments as an HList so it might not be exactly what you want.
def applyOrElse[F, I <: HList, O](
optionFun: Option[F],
input: I,
orElse: => O
)(implicit
ftp: FnToProduct.Aux[F, I => O]
): O = optionFun.fold(orElse)(f => ftp(f)(input))
Which can be used as :
val squared = Some((x:Int) => x * x)
applyOrElse(squared, 2 :: HNil, 10)
// res0: Int = 4
applyOrElse(None, 2 :: HNil, 10)
// res1: Int = 10
val concat = Some((a: String, b: String) => s"$a $b")
applyOrElse(concat, "hello" :: "world" :: HNil, "not" + "executed")
// res2: String = hello world
The getOrElse is most logical way to do it. In regards to copy/pasting it all over the place - you might not be dividing your logic up on the best way. Generally, you want to defer resolving your Options (or Futures/etc) in your code until the point you need to have it unwrapped. In this case, it seems more sensible that your function takes in an an Int and returns an Int, and you map your option where you need the result of that function.
I was browsing around and found a question about grouping a String by it's characters, such as this:
The input:
"aaabbbccccdd"
Would produce the following output:
"aaa"
"bbb"
"cccc"
"ddd"
and I found this suggestion:
val str = "aaabbbccccdd"[
val list = str.groupBy(identity).toList.sortBy(_._1).map(_._2)
And this identity fellow got me curious. I found out it is defined in PreDef like this:
identity[A](x: A): A
So basically it returns whatever it is given, right? but how does that apply in the call to groupBy?
I'm sorry if this is a basic question, is just that functional programming is still tangling my brains a little. Please let me know if there's any information I can give to make this question clearer
This is your expression:
val list = str.groupBy(identity).toList.sortBy(_._1).map(_._2)
Let's go item by function by function. The first one is groupBy, which will partition your String using the list of keys passed by the discriminator function, which in your case is identity. The discriminator function will be applied to each character in the screen and all characters that return the same result will be grouped together. If we want to separate the letter a from the rest we could use x => x == 'a' as our discriminator function. That would group your string chars into the return of this function (true or false) in map:
Map(false -> bbbccccdd, true -> aaa)
By using identity, which is a "nice" way to say x => x, we get a map where each character gets separated in map, in your case:
Map(c -> cccc, a -> aaa, d -> dd, b -> bbb)
Then we convert the map to a list of tuples (char,String) with toList.
Order it by char with sortBy and just keep the String with the map getting your final result.
To understand this just call scala repl with -Xprint:typer option:
val res2: immutable.Map[Char,String] = augmentString(str).groupBy[Char]({
((x: Char) => identity[Char](x))
});
Scalac converts a simple String into StringOps with is a subclass of TraversableLike which has a groupBy method:
def groupBy[K](f: A => K): immutable.Map[K, Repr] = {
val m = mutable.Map.empty[K, Builder[A, Repr]]
for (elem <- this) {
val key = f(elem)
val bldr = m.getOrElseUpdate(key, newBuilder)
bldr += elem
}
val b = immutable.Map.newBuilder[K, Repr]
for ((k, v) <- m)
b += ((k, v.result))
b.result
}
So groupBy contains a map into which inserts chars return by identity function.
First, let's see what happens when you iterate over a String:
scala> "asdf".toList
res1: List[Char] = List(a, s, d, f)
Next, consider that sometimes we want to group elements on the basis of some specific attribute of an object.
For instance, we might group a list of strings by length as in...
List("aa", "bbb", "bb", "bbb").groupBy(_.length)
What if you just wanted to group each item by the item itself. You could pass in the identity function like this:
List("aa", "bbb", "bb", "bbb").groupBy(identity)
You could do something silly like this, but it would be silly:
List("aa", "bbb", "bb", "bbb").groupBy(_.toString)
Take a look at
str.groupBy(identity)
which returns
scala.collection.immutable.Map[Char,String] = Map(b -> bbb, d -> dd, a -> aaa, c -> cccc)
so the key by which the elements are grouped by is the character.
Whenever you try to use methods such as groupBy on the String. It's important to note that it is implicitly converted to StringOps and not List[Char].
StringOps
The signature of groupBy is given by-
def groupBy[K](f: (Char) ⇒ K): Map[K, String]
Hence, the result is in the form -
Map[Char,String]
List[Char]
The signature of groupBy is given by-
def groupBy[K](f: (Char) ⇒ K): Map[K, List[Char]]
If it had been implicitly converted to List[Char] the result would be of the form -
Map[Char,List[Char]]
Now this should implicitly answer your curious question, as how scala figured out to groupBy on Char (see the signature) and yet give you Map[Char, String].
Basically list.groupBy(identity) is just a fancy way of saying list.groupBy(x => x), which in my opinion is clearer. It groups a list containing duplicate items by those items.
Say I have a function that checks whether some operation is applicable to an instance of A and, if so, returns an instance of B or None:
def checker[A,B]( a: A ) : Option[B] = ...
Now I want to form a new collection that contains all valid instances of B, dropping the None values. The following code seems to do the job, but there is certainly a better way:
val as = List[A]( a1, a2, a3, ... )
val bs =
as
.map( (a) => checker(a) ) // List[A] => List[Option[B]]
.filter( _.isDefined ) // List[Option[B]] => List[Option[B]]
.map( _.get ) // List[Option[B]] => List[B]
This should do it:
val bs = as.flatMap(checker)
The answer above is correct, but if you can rewrite checker, I suggest you use PartialFunction and collect. PartialFunction is a function of type A=>B that is not necessary defined for all values of A. Here is a simple example:
scala> List(1, 2, 3, 4, "5") collect {case x : Int => x + 42}
res1: List[Int] = List(43, 44, 45, 46)
collect takes an instance of PartialFunction as argument and applies it to all elements of the collection. In our case the function is defined only for Ints and "5" is filtered. So, collect is a combination of map and filter, which is exactly your case.
class DefaultListMap[A, B <: List[B]] extends HashMap[A, B] {
override def default(key: A) = List[B]()
}
I wan't to create map A -> List[B]. In my case it is Long -> List[String] but when I get key from map that doesn't have value I would like to create empty List instead of Exception being thrown. I tried different combinations but I don't know how to make code above pass the compiler.
Thanks in advance.
Why not to use withDefaultValue(value)?
scala> val m = Map[Int, List[String]]().withDefaultValue(List())
m: scala.collection.immutable.Map[Int,List[String]] = Map()
scala> m(123)
res1: List[String] = List()
Rather than using apply to access the map, you could always use get, which returns Option[V] and then getOrElse:
map.get(k) getOrElse Nil
One great feature of the scalaz functional-programming library is the unary operator ~, which means "or zero",as long as the value type has a "zero" defined (which List does, the zero being Nil of course). So the code then becomes:
~map.get(k)
This is doubly useful because the same syntax works where (for example) your values are Int, Double etc (anything for which there is a Zero typeclass).
There has been a great deal of debate on the scala mailing list about using Map.withDefault because of how this then behaves as regards the isDefinedAt method, among others. I tend to steer clear of it for this reason.
There's a method withDefaultValue on Map:
scala> val myMap = Map(1 -> List(10), 2 -> List(20, 200)).withDefaultValue(Nil)
myMap: scala.collection.immutable.Map[Int,List[Int]] = Map((1,List(10)), (2,List(20, 200)))
scala> myMap(2)
res0: List[Int] = List(20, 200)
scala> myMap(3)
res1: List[Int] = List()
Why do you want to manipulate a map when it has already a method for this?
val m = Map(1L->List("a","b"), 3L->List("x","y","z"))
println(m.getOrElse(1L, List("c"))) //--> List(a, b)
println(m.getOrElse(2L, List("y"))) //--> List(y)
withDefault can also be used.
/** The same map with a given default function.
* Note: `get`, `contains`, `iterator`, `keys`, etc are not affected
* by `withDefault`.
*
* Invoking transformer methods (e.g. `map`) will not preserve the default value.
*
* #param d the function mapping keys to values, used for non-present keys
* #return a wrapper of the map with a default value
*/
def withDefault[B1 >: B](d: A => B1): immutable.Map[A, B1]
Example:
scala> def intToString(i: Int) = s"Integer $i"
intToString: (i: Int)String
scala> val x = Map[Int, String]().withDefault(intToString)
x: scala.collection.immutable.Map[Int,String] = Map()
scala> x(1)
res5: String = Integer 1
scala> x(2)
res6: String = Integer 2
Hope this helps.
How does foldRight[B](B) from scaladoc match the actual call foldRight(0)
args is an array of integers in string representation
val elems = args map Integer.parseInt
elems.foldRight(0) (_ + _)
Scaladoc says:
scala.Iterable.foldRight[B](B)((A, B) => B) : B
Combines the elements of this list together using the binary function f, from right to left, and starting with the value z.
#note Will not terminate for infinite-sized collections.
#return f(a0, f(a1, f(..., f(an, z)...))) if the list is [a0, a1, ..., an].
And not so imporant what do the periods after f(an, z) mean?
As Steve said, the "..." are just ellipsis, indicating that a variable number of parameters that are not being shown.
Let's go to the Scaladoc, and show this step by step:
def foldRight[B](z: B)(op: (B, A) ⇒ B): B
That doesn't show enough. What is A? That is defined in the Iterable class (or whatever other class it is defined for):
trait Iterable[+A] extends AnyRef // Scala 2.7
trait Iterable[+A] extends Traversable[A] with GenericTraversableTemplate[A, Iterable[A][A]] with IterableLike[A, Iterable[A]] // scala 2.8
Ok, so A is the type of the collection. In your example, A would stand for Int:
val elems = args map Integer.parseInt
Next, [B]. That's a type parameter. Basically, the following two calls are identical in practice, but the first has the type parameter inferred by the compiler:
elems.foldRight(0) (_ + _)
elems.foldRight[Int](0) (_ + _)
If you used 0L instead of 0, then B would stand for Long instead. If you passed a "" instead of 0, then B would stand for String. You can try these out, they all will work.
So, B is Int and z is 0. Note that there are two sets parenthesis in the declaration. That means the function is curried. It receives two sets of parameters, beyond, as well as the type parameter ([B]). What that means is that you can ommit the second set of parameter, and that will return a function which takes that second set of parameter, and returns the expected result. For example:
val elemsFolder: ((Int, Int) => Int) => Int = elems.foldRight(0)
Which you could then call like this:
elemsFolder(_ + _)
Anyway, the second set receives op, which is expected to be of type (B, A) => B. Or, in other words, a function which receives two parameters -- the first being the same type as z, and the second being the same type as the type of the collection -- and returns a result of the same type as the first parameter. Since both A and B are Int, it will be a function of (Int, Int) => Int. If you passed "", then it would be a function of type (String, Int) => String.
Finally, the return type of the collection is B, which means whatever is the type of z, that will be the type returned by foldRight.
As for how foldRight works, it goes a bit like this:
def foldRight[B](z: B)(op: (B, A) => B): B = {
var acc: B = z
var it = this.reverse.elements // this.reverse.iterator on Scala 2.8
while (!it.isEmpty) {
acc = op(acc, it.next)
}
return acc
}
Which, I hope should be easy enough to understand.
Everything you need to know about foldLeft and foldRight can be gleaned from the following:
scala> List("1", "2", "3").foldRight("0"){(a, b) => "f(" + a + ", " + b + ")"}
res21: java.lang.String = f(1, f(2, f(3, 0)))
scala> List("1", "2", "3").foldLeft("0"){(a, b) => "f(" + a + ", " + b + ")"}
res22: java.lang.String = f(f(f(0, 1), 2), 3)