Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get only Right values from Either sequence

Tags:

scala

This code prints List(1, 2, ())

    def f1(i:Int): Either[String,Int] = if (i > 0) Right(1) else Left("error 1") 
    def f2(i:Int): Either[String,Int] = if (i > 0) Right(2) else Left("error 2") 
    def f3(i:Int): Either[String,Int] = if (i > 0) Right(3) else Left("error 3") 

    val seq = Seq(f1(1),f2(1),f3(-1))

    val x = seq.map { f => if (f.isRight) f.right.get }
    println(x)

I need an array filtered by isRight is true, eliminating any other values. In the example above, the result I would need is List(1, 2). How to achieve it?

like image 668
ps0604 Avatar asked Mar 09 '18 19:03

ps0604


2 Answers

Use collect and pattern match to select the case you are interested in.

seq.collect { case Right(value) => value}

Lets try on

Scala REPL

scala> :paste
// Entering paste mode (ctrl-D to finish)

    def f1(i:Int): Either[String,Int] = if (i > 0) Right(1) else Left("error 1")
    def f2(i:Int): Either[String,Int] = if (i > 0) Right(2) else Left("error 2")
    def f3(i:Int): Either[String,Int] = if (i > 0) Right(3) else Left("error 3")

    val seq = Seq(f1(1),f2(1),f3(-1))


// Exiting paste mode, now interpreting.

f1: (i: Int)Either[String,Int]
f2: (i: Int)Either[String,Int]
f3: (i: Int)Either[String,Int]
seq: Seq[Either[String,Int]] = List(Right(1), Right(2), Left(error 3))

scala> seq.collect { case Right(value) => value }
res0: Seq[Int] = List(1, 2)

Functional programming is about expressions and not statements

In

val x = seq.map { f => if (f.isRight) f.right.get }

The below returns Unit in case f is not right. So, you get Unit as third value.

if (f.isRight) f.right.get

Functional way is to use have else part also. But In this case, there is no meaningful else case.

like image 88
pamu Avatar answered Nov 03 '22 21:11

pamu


You have to remember that in Scala, if is an expression that returns a value. In your case, the value is either f.right.get (if Right is present in Either), or Unit otherwise. To filter only on Right values, use filter:

val x = seq.filter(_.isRight).map(_.right.get)
like image 6
Alex Savitsky Avatar answered Nov 03 '22 21:11

Alex Savitsky