I have the following code snapshot with repeatable boilerplate with profusion of underscore:
...............
case (a, c) =>
(a, c.map {
case (_, aParam, _, _, _, _, _, _, _, _, _) => aParam
},
c.map {
case (_, _ , cParam, _, _, _, _, _, _, _, _) => cParam
},
c.map {
case (_, _ , dParam, _, _, _, _, _, _, _, _) => dParam
}
................
c.map {
case (_, _ , _, _, _, _, _, _, _, _, eParam) => eParam
}
I would like to replace this boilerplate, but i wouldn't like to use shapeless or another library.
UPD
c has type List[(Int, String, ......, String)]
case (a, c) =>
(a, c.map(_._2).map {
case aParam => aParam
}, c.map(_._3).map {
case cParam => cParam
}, c.map(_._2).map {
case dParam => dParam
}, ..., c.map(_._11).map {
case eParam => eParam
})
This does exactly the same as your code, although I'm not sure about what aParam, cParam and others exactly are.
You could clean your code a little with the following:
case (a, c) =>
c.map{
case (c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11) =>
// do whatever processing you like here for each value in the tuple above
c2.filter(_.equals(aParam)).doStuff
...
}
You may want something like this:
//########################################################
//Old Way (If i understand ur approach correctly)
val tup1 = (7, "apple", "ball", "Cat", "dog")
val tup2 = (8, "w", "x", "y", "z")
val tup3 = (9, "r1", "r2", "r3", "r4")
var tupList: List[(Int, String, String, String, String)] = List(tup1, tup2, tup3)
tupList.foreach(item => {
item match {
case (_, "apple", _, _, _) => println("apple")
case (_, _, "x", _, _) => println("y")
case (_, _, _, _, "r4") => println("r4")
}
})
//#######################################################
//New Way ~
//Define your match filter like this: (key - position(0 based index)), ("apple", 1) ~ case (_, "apple", _, _, _)
val filter: List[(String, Int)] = List(("apple", 1), ("x", 2), ("r4", 4))
//Now, iterate through list, convert each tuple to iterator, and check each item of tuple with
//filter condition, i.e. item must match filter string and index e.g. ("apple", 1)
//Also, you don't have to worry about size of list or tuple. You can create some generic method as well using this logic.
tupList.map(tup => {
val iterator = tup.productIterator
var i = 0
while (iterator.hasNext) {
val item = iterator.next()
filter.map(f => {
val filterString = f._1
val position = f._2
if (i == position && item == filterString) {
println(tup) //matched.
}
})
i = i + 1
}
})
Related
I have an object such as:
case class Person(name: String, number: Int)
And two Sequences of this object:
Seq(("abc", 1), ("def", 2))
Seq(("abc", 300), ("xyz", 400))
I want to merge these two sequences in a single Map whose key is the names and values this separate object:
case class CombineObject(firstNumber: Option[Int], secondNumber: Option[Int])
So that my final map would look like:
Map(
"abc" -> CombineObject(Some(1), Some(300)),
"def" -> CombineObject(Some(2), None)),
"xyz" -> CombineObject(None, Some(400))
)
All I can think here is to run 2 for loops over the sequence to create the map. Is there any better way to solve the problem?
Turn each Seq into its own Map. After that it's pretty easy.
case class Person( name : String
, number : Int )
val s1 = Seq(Person("abc",1),Person("def",2))
val s2 = Seq(Person("abc",300),Person("xyz",400))
val m1 = s1.foldLeft(Map.empty[String,Int]){case (m,p) => m+(p.name->p.number)}
val m2 = s2.foldLeft(Map.empty[String,Int]){case (m,p) => m+(p.name->p.number)}
case class CombineObject( firstNumber : Option[Int]
, secondNumber : Option[Int] )
val res = (m1.keySet ++ m2.keySet).foldLeft(Map.empty[String,CombineObject]){
case (m,k) => m+(k -> CombineObject(m1.get(k),m2.get(k)))
}
//res: Map[String,CombineObject] = Map(abc -> CombineObject(Some(1),Some(300))
// , def -> CombineObject(Some(2),None)
// , xyz -> CombineObject(None,Some(400)))
This assumes that each Seq has no duplicate name entries. It's not obvious how that situation should be handled.
Another proposal with a recursive function. First, it sorts both lists by key then does the processing.
case class Person(
name: String,
number: Int
)
case class CombineObject(
firstNumber : Option[Int],
secondNumber : Option[Int]
)
val left = List(Person("abc", 1), Person("def", 2))
val right = List(Person("abc", 300), Person("xyz", 400))
def merge(left: List[Person], right: List[Person]): Map[String, CombineObject] = {
#tailrec
def doMerge(left: List[Person], right: List[Person], acc: Map[String, CombineObject] = Map.empty): Map[String, CombineObject] = {
(left, right) match {
case(Person(name1, number1) :: xs, Person(name2, number2) :: ys) =>
if(name1 == name2) {
doMerge(xs, ys, acc + (name1 -> CombineObject(Some(number1), Some(number2))))
} else {
doMerge(xs, ys, acc + (name2 -> CombineObject(None, Some(number2))) + (name1 -> CombineObject(Some(number1), None)))
}
//if both lists are always same size, next two cases are not needed
case (Nil, Person(name2, number2) :: ys) =>
doMerge(Nil, ys, acc + (name2 -> CombineObject(None, Some(number2))) )
case (Person(name1, name2) :: xs, Nil) =>
doMerge(xs, Nil, acc + (name1 -> CombineObject(None, Some(name2))))
case _ => acc
}
}
doMerge(left.sortBy(_.name), right.sortBy(_.name))
}
merge(left, right) //Map(xyz -> (None,Some(400)), def -> (Some(2),None), abc -> (Some(1),Some(300)))
Looks kind of scary :)
Another potential variation
case class Person(name : String, number : Int)
case class CombineObject(firstNumber : Option[Int], secondNumber : Option[Int])
val s1 = Seq(Person("abc",1),Person("def",2))
val s2 = Seq(Person("abc",300),Person("xyz",400))
(s1.map(_-> 1) ++ s2.map(_ -> 2))
.groupBy { case (person, seqTag) => person.name }
.mapValues {
case List((Person(name1, number1), _), (Person(name2, number2), _)) => CombineObject(Some(number1), Some(number2))
case List((Person(name, number), seqTag)) => if (seqTag == 1) CombineObject(Some(number), None) else CombineObject(None, Some(number))
case Nil => CombineObject(None, None)
}
which outputs
res1: Map[String,CombineObject] = Map(abc -> CombineObject(Some(1),Some(300)), xyz -> CombineObject(None,Some(400)), def -> CombineObject(Some(2),None)
Yet another solution, probably arguable :) ...
import scala.collection.immutable.TreeMap
case class CombineObject(firstNumber : Option[Int], secondNumber : Option[Int])
case class Person(name : String,number : Int)
val seq1 = Seq(Person("abc",1),Person("def",2))
val seq2 = Seq(Person("abc",300),Person("xyz",400))
def toExhaustiveMap(seq1:Seq[Person], seq2:Seq[Person]) = TreeMap(
seq1.map { case Person(s, i) => s -> Some(i) }: _*
) ++ ((seq2.map(_.name) diff seq1.map(_.name)).map(_ -> None))
val result = (toExhaustiveMap(seq1,seq2) zip toExhaustiveMap(seq2,seq1)).map {
case ((name1, number1), (_, number2)) => name1 -> CombineObject(number1, number2)
}
println(result)
Map(abc -> CombineObject(Some(1),Some(300)), def -> CombineObject(Some(2),None), xyz -> CombineObject(None,Some(400)))
Hope it helps.
Yet another alternative, if performance isn't a priority:
// val seq1 = Seq(("abc", 1), ("def", 2))
// val seq2 = Seq(("abc", 300), ("xyz", 400))
(seq1 ++ seq2)
.toMap
.keys
.map(k => k -> CombineObject(
seq1.collectFirst { case (`k`, v) => v },
seq2.collectFirst { case (`k`, v) => v }
))
.toMap
// Map(
// "abc" -> CombineObject(Some(1), Some(300)),
// "def" -> CombineObject(Some(2), None),
// "xyz" -> CombineObject(None, Some(400))
// )
I have an scenario where I need to call up to three services to do something. Each service has some kind of priority and my algorithm depends on the combination of the result of each service (all of them, two or even one). In order to handle this situation I want to use pattern matching (because the matchs, and variable extraction)
Here you are a simplified example.
case class Foo(bar: String, baz: Option[String])
def expensiveOperation1(): String = ???
def expensiveOperation2(): List[Int] = ???
def expensiveOperation3(): Foo = ???
lazy val r1 = expensiveOperation1()
lazy val r2 = expensiveOperation2()
lazy val r3 = expensiveOperation3()
(r1, r2, r3) match {
case ("Value1", _, _) => "1"
case ("Value2", _, _) => "2"
case (_, List(1), _) => "3"
case (_, Nil, _) => "4"
case ("Value3", 1 :: tail, _) => "5" + tail
case (_, _, Foo("x", Some(x))) => x
case (_, _, _) => "7"
}
As you can see, there is no need to call expensiveOperation2 and expensiveOperation3 all the time, but though I save each result on lazy vals, in the moment when I create Tuple3, each method is called.
I could create a container LazyTuple3 with three params call by name in order to solve that problem, but I'll get a new problem, unapply method (LazyTuple3.unapply) returns an Option, so after the first "case" each method will be called.
I could solve this with nested "if" or "match" but I want to give a chance with one "match", I find it clearer.
Any idea?
Thanks in advance.
Try to use scalaz.Need. https://static.javadoc.io/org.scalaz/scalaz_2.12/7.2.26/scalaz/Need.html
case class Foo(bar: String, baz: Option[String])
def expensiveOperation1(): String = {
println("operation1")
"Value3"
}
def expensiveOperation2(): List[Int] = {
println("operation2")
List(1, 2, 3)
}
def expensiveOperation3(): Foo = {
println("operation3")
Foo("x", Some("x"))
}
lazy val r1 = Need(expensiveOperation1())
lazy val r2 = Need(expensiveOperation2())
lazy val r3 = Need(expensiveOperation3())
(r1, r2, r3) match {
case (Need("Value1"), _, _) => "1"
case (Need("Value2"), _, _) => "2"
case (_, Need(List(1)), _) => "3"
case (_, Need(Nil), _) => "4"
case (Need("Value3"), Need(1 :: tail), _) => "5" + tail
case (_, _, Need(Foo("x", Some(x)))) => x
case (_, _, _) => "7"
}
This will print:
operation1
operation2
Let's say that I have a list of tuples:
val xs: List[(Seq[String], Option[String])] = List(
(Seq("Scala", "Python", "Javascript"), Some("Java")),
(Seq("Wine", "Beer"), Some("Beer")),
(Seq("Dog", "Cat", "Man"), None)
)
and a function that returns the index of the string if it is in the sequence of strings:
def getIndex(s: Seq[String], e: Option[String]): Option[Int] =
if (e.isEmpty) None
else Some(s.indexOf(e.get))
Now I am trying to map over xs with getIndex and return only those that I found a valid index. One way to do this is as follows:
xs.map{case (s, e) => {
val ii = getIndex(s, e) // returns an Option
ii match { // unpack the option
case Some(idx) => (e, idx)
case None => (e, -1) // give None entries a placeholder with -1
}
}}.filter(_._2 != -1) // filter out invalid entries
This approach is quite verbose and clunky to me. flatMap does not work here because I am returning a tuple instead of just the index. What is the idiomatic way to do this?
A for comprehension is one way to achieve this:
scala> val xs: List[(Seq[String], Option[String])] = List(
(Seq("Scala", "Python", "Javascript"), Some("Java")),
(Seq("Wine", "Beer"), Some("Beer")),
(Seq("Dog", "Cat", "Man"), None)
)
xs: List[(Seq[String], Option[String])] = List((List(Scala, Python, Javascript),Some(Java)), (List(Wine, Beer),Some(Beer)), (List(Dog, Cat, Man),None))
scala> def getIndex(seq: Seq[String], e: Option[String]): Option[Int] =
e.map(seq.indexOf(_)).filter(_ != -1) // notice we're doing the filter here
getIndex: getIndex[](val seq: Seq[String],val e: Option[String]) => Option[Int]
scala> for {
(seq, string) <- xs
index <- getIndex(seq, string)
s <- string
} yield (s, index)
res0: List[(String, Int)] = List((Beer,1))
There are a lot of ways to do this. One of them is this:
val result = xs.flatMap { tuple =>
val (seq, string) = tuple
string.map(s => (s, seq.indexOf(s))).filter(_._2 >= 0)
}
Maybe this looks a bit more idiomatic:
val two = xs.filter {case (s, e) => e.isDefined}
.map {case (s, e) => (e, s.indexOf(e.get)) }
.filter {case (e, i) => i > 0}
We can use the collect method to combine a map and filter:
xs.collect { case (s, e) if e.isDefined => (e, s.indexOf(e.get)) }
.filter { case (e, i) => i > 0 }
map and getOrElse might get things a little clearer:
// use map you will get Some(-1) if the element doesn't exist or None if the element is None
xs.map{case (s, e) => (e, e.map(s.indexOf(_)))}.
// check if the index is positive and use getOrElse to return false if it's None
filter{case (e, idx) => idx.map(_ >= 0).getOrElse(false)}
// res16: List[(Option[String], Option[Int])] = List((Some(Beer),Some(1)))
Or:
xs.map{ case (s, e) => (e, e.map(s.indexOf).getOrElse(-1)) }.filter(_._2 != -1)
// res17: List[(Option[String], Int)] = List((Some(Beer),1)
I have implemented a Play! 2 QueryStringBindable in Scala for a Range type. A Range consists of either a min or max value or both (of type Float). In my QueryBindable implementation I use the internalBinder to convert the two possible parameters min and max to Option[Either[String, Float]], combine them in a tuple, do a pattern match over this and finally return an Option[Either[String, Range]]. This works but as you can see in the code below the pattern match is very verbose. Is there a more concise way of doing this in Scala?
Maybe leverage higher order functions somehow to get the same result structure back?
import play.api.mvc.QueryStringBindable
case class Range(min: Option[Float], max: Option[Float])
object Range {
implicit def rangeQueryStringBindable(implicit intBinder: QueryStringBindable[Float]) = new QueryStringBindable[Range] {
override def bind(key: String, params: Map[String, Seq[String]]): Option[Either[String, Range]] = {
val minOpt = intBinder.bind("min", params)
val maxOpt = intBinder.bind("max", params)
(minOpt, maxOpt) match {
case (None, None) => None
case (Some(Right(min)), Some(Right(max))) => Some(Right(Range(Some(min), Some(max))))
case (None, Some(Right(max))) => Some(Right(Range(None, Some(max))))
case (Some(Right(min)), None) => Some(Right(Range(Some(min), None)))
case (Some(Left(minError)), Some(Left(maxError))) => Some(Left(minError))
case (Some(Left(minError)), None) => Some(Left(minError))
case (None, Some(Left(maxError))) => Some(Left(maxError))
case (Some(Right(_)), Some(Left(maxError))) => Some(Left(maxError))
case (Some(Left(minError)), Some(Right(_))) => Some(Left(minError))
}
}
override def unbind(key: String, range: Range): String = {
(range.min, range.max) match {
case (Some(min), Some(max)) => intBinder.unbind("min", min) + "&" + intBinder.unbind("max", max)
case (Some(min), None) => intBinder.unbind("min", min)
case (None, Some(max)) => intBinder.unbind("max", max)
case (None, None) => throw new IllegalArgumentException("Range without values makes no sense")
}
}
}
}
(minOpt,maxOpt) match {
case (None,None) => None
case (Some(Left(m)),_) => Some(Left(m))
case (_,Some(Left(m))) => Some(Left(m))
case (_,_) => Some(Right(Range(minOpt.map(_.right.get),maxOpt.map(_.right.get))))
}
With a couple of functions to convert an Option[Either[Error, A]] to Either[Error, Option[A]] you can end up with something a bit cleaner in my view. I also recommend renaming Range since it conflicts with a class with the same name in scala.collections.immutable.
import play.api.mvc.QueryStringBindable
case class RealRange(min: Option[Float], max: Option[Float])
object BindingEitherUtils {
implicit class OptionWithEitherFlatten[A, B](value: Option[Either[A, B]]) {
def flattenRight: Either[A, Option[B]] = {
value.map { either =>
either.right.map{ right => Some(right) }
}.getOrElse{ Right(None) }
}
}
implicit class EitherWithUnflatten[A, B](value: Either[A, Option[B]]) {
def unflattenRight: Option[Either[A, B]] = {
value.fold(left => Some(Left(left)), _.map{ right => Right(right) })
}
}
}
object RealRange {
import BindingEitherUtils._
val minError = "Invalid minimum value for RealRange"
val maxError = "Invalid maximum value for RealRange"
implicit def rangeQueryStringBindable(implicit floatBinder: QueryStringBindable[Float]) = new QueryStringBindable[RealRange] {
override def bind(key: String, params: Map[String, Seq[String]]): Option[Either[String, RealRange]] = {
val minOpt = floatBinder.bind("min", params).flattenRight
val maxOpt = floatBinder.bind("max", params).flattenRight
minOpt.left.map{ _ => minError }.right.flatMap { min =>
maxOpt.left.map{ _ => maxError }.right.flatMap { max =>
(min, max) match {
case (None, None ) =>
Right(None)
case (Some(minVal), Some(maxVal)) if minVal > maxVal =>
Left("Minimum value is larger than maximum value")
case _ =>
Right(Some(RealRange(min, max)))
}
}
}.unflattenRight
}
override def unbind(key: String, range: RealRange): String = {
(range.min, range.max) match {
case (Some(min), Some(max)) => floatBinder.unbind("min", min) + "&" + floatBinder.unbind("max", max)
case (Some(min), None) => floatBinder.unbind("min", min)
case (None, Some(max)) => floatBinder.unbind("max", max)
case (None, None) => throw new IllegalArgumentException("RealRange without values makes no sense")
}
}
}
def test(): Unit = {
val binder = rangeQueryStringBindable
Seq[(String, String)](
("10", "20"),
("10", null),
(null, "10"),
(null, null),
("asd", "asd"),
("10", "asd"),
("asd", "10"),
("asd", null),
(null, "asd"),
("20", "10")
).foreach{ case (min, max) =>
val params = Seq(
Option(min).map{ m => "min" -> Seq(m) },
Option(max).map{ m => "max" -> Seq(m) }
).flatten.toMap
val result = binder.bind("", params)
println(s"$params => $result" )
}
}
}
Which results in:
Map(min -> List(10), max -> List(20)) =>
Some(Right(RealRange(Some(10.0),Some(20.0))))
Map(min -> List(10)) =>
Some(Right(RealRange(Some(10.0),None)))
Map(max -> List(10)) =>
Some(Right(RealRange(None,Some(10.0))))
Map() =>
None
Map(min -> List(asd), max -> List(asd)) =>
Some(Left(Invalid minimum value for RealRange))
Map(min -> List(10), max -> List(asd)) =>
Some(Left(Invalid maximum value for RealRange))
Map(min -> List(asd), max -> List(10)) =>
Some(Left(Invalid minimum value for RealRange))
Map(min -> List(asd)) =>
Some(Left(Invalid minimum value for RealRange))
Map(max -> List(asd)) =>
Some(Left(Invalid maximum value for RealRange))
Map(min -> List(20), max -> List(10)) =>
Some(Left(Minimum value is larger than maximum value))
Yes, it can be simplified.
For the bind method you can place a few wildcards, when you have errors to simplify it. That way you only have 4 permutations for the Range assembly logic. I wouldn't do too much magic here as it would complicate understanding your code.
override def bind(key: String, params: Map[String, Seq[String]]): Option[Either[String, Range]] = {
val minOpt = intBinder.bind("min", params)
val maxOpt = intBinder.bind("max", params)
(minOpt, maxOpt) match {
case (None, None) => None
case (Some(Right(min)), Some(Right(max))) => Some(Right(Range(Some(min), Some(max))))
case (None, Some(Right(max))) => Some(Right(Range(None, Some(max))))
case (Some(Right(min)), None) => Some(Right(Range(Some(min), None)))
// Error handling
case (Some(Left(minError)), _) => Some(Left(minError))
case (_, Some(Left(maxError))) => Some(Left(maxError))
}
}
For the unbind I would use a different approach, by utilizing Option's map function and then combining them into a Iterable you can call mkString and it will do nothing for 1 string and append a & if there are two strings. The code example has types, so you can understand easier.
def unbind(key: String, range: Range): String = {
val minString: Option[String] = range.min.map(min => intBinder.unbind("min", min))
val maxString: Option[String] = range.max.map(max => intBinder.unbind("max", max))
val strings: Iterable[String] = minString ++ maxString
strings match {
case Nil => throw new IllegalArgumentException("Range without values makes no sense")
case _ => strings.mkString("&")
}
}
And if you're into short code:
def unbind(key: String, range: Range): String = {
val minString = range.min.map(min => intBinder.unbind("min", min))
val maxString = range.max.map(max => intBinder.unbind("max", max))
minString ++ maxString match {
case Nil => throw new IllegalArgumentException("Range without values makes no sense")
case strings => strings.mkString("&")
}
}
I have an automatically generated client for an web service. I has many complicated classes and I have to do a pattern matching against it. For now I have a structure looking like this:
val response = client.getResponse
response match {
case Left(_) => None
case Right(a: SomeClass) => a match {
case SomeClass2(b: Option[SomeClass3]) => b match {
case None => None
case Some(c: SomeClass3) => c match {
case SomeClass4(_, _, _, _, d: Seq[SomeClass4]) => d match {
case Nil => None
case seq: Seq[SomeClass5] => seq match {
case Nil => None
case Seq(xs#_*) => xs map { x =>
x match {
case Nil => None
case SomeClass6(e: SomeClass7) => e match {
case Nil => None
case SomeClass8(f, _, _, _, _) => f match {
case Nil => None
case Seq(xs#_*) => xs map { x =>
x match {
case Nil => None
case SomeClass9(g: Seq[SomeClass9], _, _, _, _, _, _, _, _, _, _) => /* + some nested levels more*/
}
}
}
}
}
}
}
}
}
}
}
where SomeClass1 - SomeClass9 are case classes.
As you can see, it seems frightening. What do I do about it? What's the standard way to make it look nicer?
I guess there should be not only refactoring but rather another approach.
Assuming that a should be SomeClass2, but not SomeClass (same with b, c, d).
You could use alternative patterns like case A | B => ... and structural patterns like Some(MyClass(f)).
Also you could use partial function in map like map { case ... } instead of map { x => x match {...} }.
And I guess there is a error in your code: there is check for case Nil => ...; case SomeClass8(...) => ....
You could replace Seq(xs #_*) with xs. If you need entire collection you don't need to extract elements.
Your code:
response match {
case Left(_) | Right(SomeClass2(None)) | Right(SomeClass2(Some(SomeClass3(_, _, _, _, Nil))) => None
case Right(SomeClass2(Some(SomeClass3(_, _, _, _, xs))) =>
xs map {
case SomeClass6(None) | SomeClass6(Some(SomeClass8(Nil, _, _, _, _))) => None
case SomeClass6(Some(SomeClass8(xs, _, _, _, _))) =>
xs map {
case Nil => None
case SomeClass9(g, _, _, _, _, _, _, _, _, _, _) => /* + some nested levels more*/
}
}
}
You should also extract nested matches to separate methods.
Pattern matching is not the only solution. You could use methods of Either and Option:
response.right.toOption.collect {
// No need for the first part.
case SomeClass2(Some(SomeClass3(_, _, _, _, xs)) if xs.nonEmpty => ...
}
You might find extractors useful. It might also be worth flattening some of the cases so you have
case Right(SomeClass(SomeClass2(Some(SomeClass3(value))))) => value ...
case _ => None
rather than having a None case explicitly defined at each level.
You can probably reduce a lot of this complexity by using for comprehensions rather than pattern matching.
One simple opportunity is where you are mapping a sequence to yet another pattern match:
case seq: Seq[SomeClass5] => seq match {
case Nil => None
case Seq(xs#_*) => xs map { x =>
x match {
...
}
}
}
This is very ugly because you have used match to eliminate the Nil case and then matched seq again. Two levels of match to deal with one object. This could become
case seq: Seq[SomeClass5] => for (x <- seq) yield {
x match {
...
}
}
This eliminates the Nil case check and removes a couple of layers of nesting, which is a big win. And you do this in at least two layers, so that's an even bigger win. Of course, this returns a (possibly Nil) sequence rather than f(x) or None, but you can easily convert that. One way to do this, without adding another of nesting, would be this:
case seq: Seq[SomeClass5] => (for (x <- seq) yield {
x match {
...
}
}) match {
case Nil => None
case Seq(i) => Some(i)
case ...
}
Or, if (as I suspect) you expect these sequences only to have one element in them...
case seq: Seq[SomeClass5] => (for (x <- seq) yield {
x match {
...
}
}) match {
case Seq(i) => Some(i)
case _ => None
}