condition matching in an array with case class in scala - scala

I have a task need to find a particular string in an array:
1. if found, return its value;
2. if not found, return -1.
I wrote an "idea" code, but I don't know how to finish it correctly.
case class person(name:String, value: Int)
personList[Array[person]]
val result = personList match {
case x if x.name == "john" => x.value
case _ => -1 }
the complier reports errors at "case x if x.name"

Would this work for you?
persons.find(_.name == "john").fold(-1)(_.value)
Note: I've left the creation and/or population of the persons array up to you.

val result = personList.find(_.name=="john") match {
case some(x) => x.value
case None => -1 }

Related

Scala way of coding

I am moving from C / C++to Scala, and following is my code -
something match {
case one: {
if (some_list.nonEmpty) {
if (some_list size == 1 && some_list contains == something)
fill a form(use something in a certain way)
else if (some_list size == 1 && some_list contains == soemthing_else)
fill a form(use something_else in a certain way)
else {
if (some_var.nonEmpty) {
fill a form(use some_var)
} else {
fill a form(without using some_var)
}
}
} else {
if (another_var has certain value || another_var has certain value 2) {
fill a form(using another_var)
} else {
fill a form(without using another_var)
}
} //if (some_list.nonEmpty) ends
} // case ends
case two: one liner code
case _: one liner code
} //match ends
Looking
for guidance to write it in a nice scala way using its features and strengths.
Thank you
I am making a few assumptions to make this work:
trait cases
case object one extends cases
case object two extends cases
case object three extends cases
case object four extends cases
val someList: List[cases] = List(one, two)
val something: cases = one
val somethingElse: cases = two
val someVar: Option[String] = Option("someVar")
val someOtherVar: Option[String] = Option("someOtherVar")
val anotherVar: Option[String] = Option("anotherVar")
Following is a simplified version of your code using the above:
something match {
case `one` =>
someList match {
case head :: Nil if(head == something) => println("one")
case head :: Nil if(head == somethingElse) => println("two")
case head :: tail if(someVar.nonEmpty) => println("someVar")
case head :: tail if(someOtherVar.nonEmpty) => println("someOtherVar")
case head :: tail => println("not using someOtherVar")
case Nil if(anotherVar.nonEmpty) => println("anotherVar")
case Nil => println("not using anotherVar")
}
case `two` => println("two")
case _ => println("rest")
}

Scala: How to add match vals to a list val

I have a few vals that match for matching values
Here is an example:
val job_ = Try(jobId.toInt) match {
case Success(value) => jobs.findById(value).map(_.id)
.getOrElse( Left(WrongValue("jobId", s"$value is not a valid job id")))
case Failure(_) => jobs.findByName(jobId.toString).map(_.id)
.getOrElse( Left(WrongValue("jobId", s"'$jobId' is not a known job title.")))
}
// Here the value arrives as a string e.i "yes || no || true || or false" then converted to a boolean
val bool_ = bool.toLowerCase() match {
case "yes" => true
case "no" => false
case "true" => true
case "false" => false
case other => Left(Invalid("bool", s"wrong value received"))
}
Note: invalid case is case class Invalid(x: String, xx: String)
above i'm looking for a given job value and checking whether it exist in the db or not,
No I have a few of these and want to add to a list, here is my list val and flatten it:
val errors = List(..all my vals errors...).flatten // <--- my_list_val (how do I include val bool_ and val job_)
if (errors.isEmpty) { do stuff }
My result should contain errors from val bool_ and val job_
THANK!
You need to fix the types first. The type of bool_ is Any. Which does not give you something you can work with.
If you want to use Either, you need to use it everwhere.
Then, the easiest approach would be to use a for comprehension (I am assuming you're dealing with Either[F, T] here, where WrongValue and Invalid are both sub-classes of F and you're not really interested in the errors).
for {
foundJob <- job_
_ <- bool_
} yield {
// do stuff
}
Note, that in Scala >= 2.13 you can use toIntOption when converting the String to Int:
vaj job_: Either[F, T] = jobId.toIntOption match {
case Some(value) => ...
case _ => ...
}
Also, in case expressions, you can use alternatives when you have the same statement for several cases:
val bool_: Either[F, Boolean] = bool.toLowerCase() match {
case "yes" | "true" => Right(true)
case "no" | "false" => Right(false)
case other => Left(Invalid("bool", "wrong value received"))
}
So, according to your question, and your comments, these are the types you're dealing with.
type ID = Long //whatever id is
def WrongValue(x: String, xx: String) :String = "?-?-?"
case class Invalid(x: String, xx: String)
Now let's create a couple of error values.
val job_ :Either[String,ID] = Left(WrongValue("x","xx"))
val bool_ :Either[Invalid,Boolean] = Left(Invalid("x","xx"))
To combine and report them you might do something like this.
val errors :List[String] =
List(job_, bool_).flatMap(_.swap.toOption.map(_.toString))
println(errors.mkString(" & "))
//?-?-? & Invalid(x,xx)
After checking types as #cbley explained. You can just do a filter operation with pattern matching on your list:
val error = List(// your variables ).filter(_ match{
case Left(_) => true
case _ => false
})

Scala - How to return Option[String] instead of Any with pattern matching?

I wanted to get Sale objects from HBase concatenated with their HBase ids (a string representation of ImmutableBytesWritable) as Option[String].
First I've implemented processSales method so that it just returned all sales + hBase ids as shown below:
private def processSales (result: Result, hBaseId: String): Option[String] = {
val triedSale: Try[Sale] = myThriftCodec.invert(result.getValue("binary", "object"))
triedSale match {
case Success(sale) => Some(hBaseId + sale)
case _ => None
}
}
Now I want to return only those concatenated hBaseIds + Sales where Sales have metric_1 == null
So I tried the following:
private def processSales (result: Result, hBaseId: String): Any = {
val triedSale: Try[Sale] = myThriftCodec.invert(result.getValue("binary", "object"))
triedSale match {
case Success(sale) => Some(hBaseId + sale)
case _ => None
}
triedSale match {
case someSale => if (someSale.get.metric_1 = null) someSale.map(sale => hBaseId + sale)
}
}
But it seems that I'm missing something here and the method returns Any even if I wrap this like this Option(hBaseId + sale).
What should I fix in my logic in order to return Option[String] with sales having metric_1 == null ?
UPD: Downvoting without pointing out the problems with my question doesn't make sense. It just totally demotivates seeking new knowledge.
You are missing the second option of the match case in your else, so it's returning Unit when the metric is not null, so Unit in one case, and Option(String) in another, the compiler guess that you want Any as return type
What do you want to return when the metric_1 is not null? In this example you return the exact same input:
triedSale match {
case someSale => if (someSale.get.metric_1 = null) someSale.map(s => hBaseId + s) else someSale
}
Or in a more elegant way you can do:
triedSale match {
case Success(metric_1) if metric_1 = null => Some(hBaseId + metric_1)
case Success(metric_1) if metric_1 != null => triedSale
case _ => None
}
EDIT
As per the comments, you only want to return something when the metric_1 is null so here is the best solution as for my understanding:
Also why are you pattern matching the same variable twice?
triedSale match {
case someSale => if (someSale.get.metric_1 = null) someSale.map(s => hBaseId + s) else None
}
Or something like this:
triedSale match {
case Success(metric_1) if metric_1 = null => Some(hBaseId + metric_1)
case _ => None
}
Isn't just as simple as below?
myThriftCodec.invert(result.getValue("binary", "object"))
.toOption
.filter(_.metric_1 == null)
.map(hBaseId+_)

Pattern Matching Case Match using Scala

Having issues with trying to get my case match to work as expected.
The outcome I am looking for is as follows:
case 1 OR 2 => randomly select one reference
case any other number above 2 => randomly select (number - 2) reference
case None => throw exception
Im having problems implementing this. so far I have:
val randomList: List = actualList.size match {
case 1 => scala.util.Random.shuffle(actualList).take(1)
case x? => scala.util.Random.shuffle(actualList).take(2)
case None => throw new IllegalStateException("references have not been generated successfully.")
}
I get an error message with the 'None' stating the pattern type is incompatible with expected type Int.
If there is a better way to implement this, please do share.
Any help would be much appreciated.
Thanks
I think you can shuffle right away to simplify each expression in case clauses:
val actualList = List(1, 2, 3)
val shuffled = Random.shuffle(actualList)
shuffled.size match {
case 0 => throw new RuntimeException()
case 1 | 2 => shuffled.take(1)
case _ => shuffled.take(2)
}
You can use |, guard and _ to achieve this
val randomList: List = actualList.size match {
case 0 => throw new IllegalStateException("references have not been generated successfully.")
case 1 | 2 => scala.util.Random.shuffle(actualList).take(1)
case _ => scala.util.Random.shuffle(actualList).take(2)
}

map expression in case clause in scala pattern matching

I have a configuration value that matches to one of the values in a map and depending on to which it matches i take an action. Here is some sample code of what i am trying to do
val x = 1 // or 2 or 3
val config = Map("c1"-> 1, "c2"-> 2, "c3"-> 3)
x match {
case config("c1") =>
println("1")
case config("c2") =>
println("2")
case config("c3") =>
println("3")
}
Now this should print 1 because config("c1") evaluates to 1 but it gives error
error: value config is not a case class, nor does it have an unapply/unapplySeq member
case config("c1") =>
Similarly for the other 2 cases. Why should i have an unapply here? Any pointers?
An expression like that looks like an extractor, hence the message about unapply/unapplySeq methods. If you don't want to use an extractor but just want to match against a plain value, you need to store that value in a stable identifier - you can't use an arbitrary expression as a match case:
val case1 = config("c1")
x match {
case case1 => println("1")
...
}
To the best of my knowledge, in Scala, x match {case config("c1") gets translated to config.unapply(x) with the branching dependent on the result of the unapply method. As Imm already mentioned in his answer, this isn't the case for stable identifiers (literals and val), and I'd encourage you to use his solution.
Nevertheless, to show you how you could solve the problem using extractors, I'd like to post a different solution:
def main(args: Array[String]): Unit = {
object config {
val configData = Map("c1" -> 1, "c2" -> 2, "c3" -> 3)
def unapply(value: Int): Option[String] = configData find (_._2 == value) map (_._1)
}
1 to 4 foreach {
case config("c1") => println("1")
case config("c2") => println("2")
case config("c3") => println("3")
case _ => println("no match")
}
}
I changed the match for a foreach to show the different results, but this has no effect on the implementation. This would print:
1
2
3
no match
As you can see, case config("c1") now calls the unapply method and checks whether the result is Some("c1"). Note that this is inverse to how you'd use a map: The key is searched according to the value. However, this makes sense: If in the map, "c1" and "c2" both map to 1, then 1 matches both, the same way _ matches everything, in our case even 4 which is not configured.
Here's also a very brief tutorial on extractors. I don't find it particularly good, because both, the returned type and the argument type are Int, but it might help you understand what's going on.
As others have stated, with x match { case config("c1") => ..., scala looks for an extractor by the name of config (something with an unapply method that takes a single value and returns an Optional value); Making pattern matching work this way seems like an abuse of the pattern, and I would not use an extractor for this.
Personally, I would recommend one of the following:
if (x == config("c1"))
println("1")
else if (x == config("c2"))
println("2")
else ...
Or, if you're set on using a match statement, you can use conditionals like this:
x match {
case _ if x == config("c1") =>
println("1")
case _ if x == config("c2") =>
println("2")
case _ if x == config("c3") =>
println("3")
}
Not as clean; unfortunately, there isn't a way to invoke a method call literally where the extractor goes. You can use back-ticks to tell scala "match against the value of this variable" (rather than default behavior, which would yield the value named as that variable):
val (c1,c2,c3) = (config("c1"), config("c2"), config("c3"))
x match {
case `c1` =>
println("1")
case `c2` =>
println("2")
case `c3` =>
println("3")
}
Finally, if your goal is to reverse-apply a map, maybe try this instead?
scala> Map("a" -> 1).map { case (k,v) => (v,k) }
res0: scala.collection.immutable.Map[Int,String] = Map(1 -> a)