Scala pattern match on subset of random elements in a List - scala

Can anybody suggest a efficient style to pattern match on a subset of elements in a list
containsSlice expects order and does not work with an unordered comparator list
This is what I am looking for (an inaccurate syntactical representation to drive the point)
List(1,2,3,4,5,6) match {
case x if x.contains(List(1,3)) => do something
case x if x.contains(List(2)) => else
case _ => do something else else
}

If you can live without the pattern-match,
a single "subset of elements in a list" can be identified by checking if each element in the subset is contained in the list, like such:
if( List(3,1).forall( List(1,2,3,4,5,6).contains(_) ) ) println("do something")

List(1, 2, 3, 4, 5, 6).toSet match {
case x if Set(1, 3).subsetOf(x) => println("do something")
case x if Set(2).subsetOf(x) => println("something else")
case _ => println("another thing")
}

you mean something like this? :
def [X]containsSubset(li:List[X],li2:List[X]) =
li2 match {
case Nil => true
case hd::_ => li.contains(hd) && containsSubset(li,tl)
}

Related

how to print the index of failure in catch expression in scala?

I have a code looking like this:
import scala.util.{Try, Success, Failure}
Try(
for (i <- 1 to 1000) {
doSomething(df(i))
}
) match {
case Success(t) => println(s"success")
case Failure(t) => println(s"failure")
}
i want to print the index of the failed input. how to print the index i in catch expression?
You can do this instead using Cats:
import scala.util.Try
import cats.implicits._
(1 to 1000).traverse(i => Try(doSomething(df(i))).toEither.left.map(ex => (ex, i))) match {
case Right(_) => println("success")
case Left((ex, i)) => println(s"failure: ${ex.getMessage} on idx: ${i}")
}
If you do not want to use Cats, you can just:
val attempts = for {
i <- Stream.range(start = 1, end = 1000) // Thanks to Bogdan for the idea of using a Stream.
} yield Try(doSomething(df(i))).toEither.left.map(ex => (ex, i))
attempts.collectFirst { case Left((ex, i)) => ex -> i } match {
case None => println("success")
case Some((ex, i)) => println(s"failure: ${ex.getMessage} on idx: ${i}")
}
You should definitely follow Luis's answer, but to address your comment, you could also catch IllegalArgumentException and re-throw it with the added index to the message, perhaps something like so:
Try(
for (i <- 1 to 1000) {
try doSomething(i) catch { case e: IllegalArgumentException => throw new IllegalArgumentException(s"Failed with index $i", e)}
}
) match {
case Success(t) => println(s"success")
case Failure(t) => println(s"failure", t)
}
However this seems hideous, and I do not advise it.
IMO the question hints that the code is lying.
you could write the code differently:
import scala.util.{Try, Success, Failure}
for (i <- 1 to 1000) {
Try(
doSomething(df(i))
) match {
case Failure(t) => println(s"failure on $i")
case _ =>
}
}
But you don't want to. Why not? Because you want to stop the iteration after the first failure. But you're using loop from 1 to 1000. You don't really intend to do the whole 1000 iterations. You're using an exception to break a for loop.
I would rewrite this code to make it clear that i don't intend to iterate the entire range explicitly.
You could, for example, use find instead of for, to find the index that causes a failure to happen. if None was found -> everything was successful.
so something similar to (untested):
(1 to 1000).indexWhere{index=>Try{doSomething(index)}.isFailure
i'm not sure if it's find or indexWhere in scala but you get the idea.
if you would like to obtain the exception as well, not just the index you could use views (https://docs.scala-lang.org/overviews/collections/views.html) to change your sequence to a lazily evaluated one, map the list to a tuple of form (index, Try) (without iterating the entire collection, due to lazyness of .view result), and then collectFirst where second element of tuple is Failure.
so something like (untested):
(1 to 1000).view.map{index => (index, doSomething(index)}.collectFirst{case (i,Failure(e)) => println(s"error was $e at index $i")}
alternatively you could write a very very small recursion to iterate the index sequence (also untested)
def findException(indexes: Seq[Int]): Option[(Int, Exception)] = indexes match {
case Nil => None
case index+:remaining =>
Try(doSomething(i)) match {
case Success(_) => findException(remaining)
case Failure(e) => Option((index,e))
}
findException(1 to 1000).map(println)
one question is how did you determine 1 to 1000?
this question would look differently if you had a collection of elements to verify, and not a range. in that case you would probably just use foldLeft.

condition matching in an array with case class in 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 }

Scala filter return only one (or specific number) of results

What is the best Scala idiomatic approach to verify that filter returns only one results (or specific amount in that matter), and if the amount correct, to continue with it?
For example:
val myFilteredListWithDesiredOneItem = unfilteredList
.filter(x => x.getId.equals(something))
.VERIFY AMOUNT
.toList
Consider this for a list of type T,
val myFilteredListWithDesiredOneItem = {
val xs = unfilteredList.filter(x => x.getId.equals(something))
if (xs.size == n) xs.toList
else List.empty[T]
}
Not a oneliner, the code remains simple none the less.
Try a match with guards, perhaps?
list.filter(...) match {
case Nil => // empty
case a if (a.size == 5) => // five items
case b#(List(item1, item2) => // two (explicit) items
case _ => // default
}
Something like this perhaps:
Option(list.filter(filterFunc))
.filter(_.size == n)
.getOrElse(throw new Exception("wrong size!"))

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)

Scala match case on regex directly

I am trying to do something like the following:
list.foreach {x =>
x match {
case """TEST: .*""" => println( "TEST" )
case """OXF.*""" => println("XXX")
case _ => println("NO MATCHING")
}
}
The idea is to use it like groovy switch case regex match. But I can't seem to get to to compile. Whats the right way to do it in scala?
You could either match on a precompiled regular expression (as in the first case below), or add an if
clause. Note that you typically don't want to recompile the same regular expression on each case evaluation, but rather have it on an object.
val list = List("Not a match", "TEST: yes", "OXFORD")
val testRegex = """TEST: .*""".r
list.foreach { x =>
x match {
case testRegex() => println( "TEST" )
case s if s.matches("""OXF.*""") => println("XXX")
case _ => println("NO MATCHING")
}
}
See more information here and some background here.
Starting Scala 2.13, it's possible to directly pattern match a String by unapplying a string interpolator:
// val examples = List("Not a match", "TEST: yes", "OXFORD")
examples.map {
case s"TEST: $x" => x
case s"OXF$x" => x
case _ => ""
}
// List[String] = List("", "yes", "ORD")