How to check if there is [Option [_]] in the list and return the element name?

I have several Option . I want to check if they matter. If Option is None , I want to answer the user about this. Left.

This is what I did:

 val name:Option[String] val email:Option[String] val pass:Option[String] val i = List(name,email,pass).find(x => x match{ case None => true case _ => false }) i match{ case Some(x) => Ok("Bad Request") case None => { //move forward } } 

Above, I can replace find with contains , but this is a very dirty way. How can I make it elegant and monadic?

Edit: I would also like to know which item was None .

+6
source share
8 answers

Another way is to understand:

 val outcome = for { nm <- name em <- email pwd <- pass result = doSomething(nm, em, pwd) // where def doSomething(name: String, email: String, password: String): ResultType = ??? } yield (result) 

This will generate the outcome as Some(result) , which you can query in various ways (all methods are available for collection classes: map, filter, foreach, etc.). For instance:

 outcome.map(Ok(result)).orElse(Ok("Bad Request")) 
+6
source
  val ok = Seq(name, email, pass).forall(_.isDefined) 
+6
source
 val response = for { n <- name e <- email p <- pass } yield { /* do something with n, e, p */ } response getOrElse { /* bad request /* } 

Or, using Scalaz:

 val response = (name |@| email |@| pass) { (n, e, p) => /* do something with n, e, p */ } response getOrElse { /* bad request /* } 
+4
source

If you want to reuse the code, you can do

 def allFieldValueProvided(fields: Option[_]*): Boolean = fields.forall(_.isDefined) 

If you want to know all the missing values, you can find all the missing values, and if they are not, then you will be fine.

 def findMissingValues(v: (String, Option[_])*) = v.collect { case (name, None) => name } val missingValues = findMissingValues(("name1", option1), ("name2", option2), ...) if(missingValues.isEmpty) { Ok(...) } else { BadRequest("Missing values for " + missingValues.mkString(", "))) } 
+4
source
 if ((name :: email :: pass :: Nil) forall(!_.isEmpty)) { } else { // bad request } 
+3
source

I think the easiest way would be the following:

 (name,email,pass) match { case ((Some(name), Some(email), Some(pass)) => // proceed case _ => // Bad request } 
+2
source

Version with stone knives and bear skin:

 import util._ object Test extends App { val zero: Either[List[Int], Tuple3[String,String,String]] = Right((null,null,null)) def verify(fields: List[Option[String]]) = { (zero /: fields.zipWithIndex) { (acc, v) => v match { case (Some(s), i) => acc match { case Left(_) => acc case Right(t) => val u = i match { case 0 => t copy (_1 = s) case 1 => t copy (_2 = s) case 2 => t copy (_3 = s) } Right(u) } case (None, i) => val fails = acc match { case Left(f) => f case Right(_) => Nil } Left(i :: fails) } } } def consume(name: String, email: String, pass: String) = Console println s"$name/$email/$pass" def fail(is: List[Int]) = is map List("name","email","pass") foreach (Console println "Missing: " + _) val name:Option[String] = Some("Bob") val email:Option[String]= None val pass:Option[String] = Some("boB") val res = verify(List(name,email,pass)) res.fold(fail, (consume _).tupled) val res2 = verify(List(name, Some(" bob@bob.org "),pass)) res2.fold(fail, (consume _).tupled) } 

The same thing, using reflection to generalize a copy of the tuple.

The disadvantage is that you have to say which tuple to expect. In this form, the reflection is similar to one of those achievements of the Stone Age that were so magical that they stretched on Twitter for ten thousand years.

  def verify[A <: Product](fields: List[Option[String]]) = { import scala.reflect.runtime._ import universe._ val MaxTupleArity = 22 def tuple = { require (fields.length <= MaxTupleArity) val n = fields.length val tupleN = typeOf[Tuple2[_,_]].typeSymbol.owner.typeSignature member TypeName(s"Tuple$n") val init = tupleN.typeSignature member nme.CONSTRUCTOR val ctor = currentMirror reflectClass tupleN.asClass reflectConstructor init.asMethod val vs = Seq.fill(n)(null.asInstanceOf[String]) ctor(vs: _*).asInstanceOf[Product] } def zero: Either[List[Int], Product] = Right(tuple) def nextProduct(p: Product, i: Int, s: String) = { val im = currentMirror reflect p val ts = im.symbol.typeSignature val copy = (ts member TermName("copy")).asMethod val args = copy.paramss.flatten map { x => val name = TermName(s"_$i") if (x.name == name) s else (im reflectMethod (ts member x.name).asMethod)() } (im reflectMethod copy)(args: _*).asInstanceOf[Product] } (zero /: fields.zipWithIndex) { (acc, v) => v match { case (Some(s), i) => acc match { case Left(_) => acc case Right(t) => Right(nextProduct(t, i + 1, s)) } case (None, i) => val fails = acc match { case Left(f) => f case Right(_) => Nil } Left(i :: fails) } }.asInstanceOf[Either[List[Int], A]] } def consume(name: String, email: String, pass: String) = Console println s"$name/$email/$pass" def fail(is: List[Int]) = is map List("name","email","pass") foreach (Console println "Missing: " + _) val name:Option[String] = Some("Bob") val email:Option[String]= None val pass:Option[String] = Some("boB") type T3 = Tuple3[String,String,String] val res = verify[T3](List(name,email,pass)) res.fold(fail, (consume _).tupled) val res2 = verify[T3](List(name, Some(" bob@bob.org "),pass)) res2.fold(fail, (consume _).tupled) 
+2
source

I know this does not scale well, but is that enough?

 (name, email, pass) match { case (None, _, _) => "name" case (_, None, _) => "email" case (_, _, None) => "pass" case _ => "Nothing to see here" } 
+1
source

Source: https://habr.com/ru/post/951923/


All Articles