Modifying the list while using for comprehension in Scala - scala

I have a list that contains all possible deals between clients, and every sell-buy combination needs to be compared. With the comparison, another list need to be modified.
I have the following code:
def res(input_orders: List[Order], input_clients: List[Client]): List[Client] = {
for {
order1 <- input_orders
order2 <- input_orders if check_order(order1, order2)
firstClient = input_clients.find(_.name == order1.client)
secondClient = input_clients.find(_.name == order2.client)
tmp <- if (order1.operation == 's') {
input_clients.map { case `firstClient` => sell(firstClient.get, order1); case x => x }
input_clients.map { case `secondClient` => buy(secondClient.get, order2); case x => x }
} else {
input_clients.map { case `firstClient` => buy(firstClient.get, order1); case x => x }
input_clients.map { case `secondClient` => sell(secondClient.get, order2); case x => x }
}
} yield tmp
}
But it returns the list of clients as it is and does not modify it.
I suppose that the problem is in this "modification" block:
input_clients.map { case `firstClient` => sell(firstClient.get, order1); case x => x }
input_clients.map { case `secondClient` => buy(secondClient.get, order2); case x => x }
} else {
input_clients.map { case `firstClient` => buy(firstClient.get, order1); case x => x }
input_clients.map { case `secondClient` => sell(secondClient.get, order2); case x => x }
What is wrong with it?

Recall that the map function is immutable which means it doesn't do any modification to the datastructure but rather returns a new object which content has been updated.
In the block you're mentioning, the first calls of mapare useless because the return value is never used. A proper way of achieving the task you initially wanted to do would be:
val order = order1.operation == 's'
input_clients.map {
case `firstClient` => if (order) sell(firstClient.get, order1) else buy(firstClient.get, order1)
case `secondClient` => if (order) buy(secondClient.get, order2) else sell(secondClient.get, order2)
case x => x
}
Moreover, avoid using the get accessor of an Option[T] (imagine what would happen if the option was None). Prefer safer operations like pattern matching or flatMap / for-comprehension instead.

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 using calculations from pattern matching's guard (if) in body

I'm using pattern matching in scala a lot. Many times I need to do some calculations in guard part and sometimes they are pretty expensive. Is there any way to bind calculated values to separate value?
//i wan't to use result of prettyExpensiveFunc in body safely
people.collect {
case ...
case Some(Right((x, y))) if prettyExpensiveFunc(x, y) > 0 => prettyExpensiveFunc(x)
}
//ideally something like that could be helpful, but it doesn't compile:
people.collect {
case ...
case Some(Right((x, y))) if {val z = prettyExpensiveFunc(x, y); y > 0} => z
}
//this sollution works but it isn't safe for some `Seq` types and is risky when more cases are used.
var cache:Int = 0
people.collect {
case ...
case Some(Right((x, y))) if {cache = prettyExpensiveFunc(x, y); cache > 0} => cache
}
Is there any better solution?
ps: Example is simplified and I don't expect anwers that shows that I don't need pattern matching here.
You can use cats.Eval to make expensive calculations lazy and memoizable, create Evals using .map and extract .value (calculated at most once - if needed) in .collect
values.map { value =>
val expensiveCheck1 = Eval.later { prettyExpensiveFunc(value) }
val expensiveCheck2 = Eval.later { anotherExpensiveFunc(value) }
(value, expensiveCheck1, expensiveCheck2)
}.collect {
case (value, lazyResult1, _) if lazyResult1.value > 0 => ...
case (value, _, lazyResult2) if lazyResult2.value > 0 => ...
case (value, lazyResult1, lazyResult2) if lazyResult1.value > lazyResult2.value => ...
...
}
I don't see a way of doing what you want without creating some implementation of lazy evaluation, and if you have to use one, you might as well use existing one instead of rolling one yourself.
EDIT. Just in case you haven't noticed - you aren't losing the ability to pattern match by using tuple here:
values.map {
// originial value -> lazily evaluated memoized expensive calculation
case a # Some(Right((x, y)) => a -> Some(Eval.later(prettyExpensiveFunc(x, y)))
case a => a -> None
}.collect {
// match type and calculation
...
case (Some(Right((x, y))), Some(lazyResult)) if lazyResult.value > 0 => ...
...
}
Why not run the function first for every element and then work with a tuple?
Seq(1,2,3,4,5).map(e => (e, prettyExpensiveFunc(e))).collect {
case ...
case (x, y) if y => y
}
I tried own matchers and effect is somehow OK, but not perfect. My matcher is untyped, and it is bit ugly to make it fully typed.
class Matcher[T,E](f:PartialFunction[T, E]) {
def unapply(z: T): Option[E] = if (f.isDefinedAt(z)) Some(f(z)) else None
}
def newMatcherAny[E](f:PartialFunction[Any, E]) = new Matcher(f)
def newMatcher[T,E](f:PartialFunction[T, E]) = new Matcher(f)
def prettyExpensiveFunc(x:Int) = {println(s"-- prettyExpensiveFunc($x)"); x%2+x*x}
val x = Seq(
Some(Right(22)),
Some(Right(10)),
Some(Left("Oh now")),
None
)
val PersonAgeRank = newMatcherAny { case Some(Right(x:Int)) => (x, prettyExpensiveFunc(x)) }
x.collect {
case PersonAgeRank(age, rank) if rank > 100 => println("age:"+age + " rank:" + rank)
}
https://scalafiddle.io/sf/hFbcAqH/3

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 - dynamically choose function

I'm trying to dynamically choose a function, as follows:
val yld: (Nothing => Object) = {
column.getType match {
case PrimitiveType.PrimitiveTypeName.BINARY => new String(creader.getBinary.getBytes)
case PrimitiveType.PrimitiveTypeName.BOOLEAN => creader.getBoolean
case PrimitiveType.PrimitiveTypeName.DOUBLE => creader.getDouble
case PrimitiveType.PrimitiveTypeName.FLOAT => creader.getFloat
case PrimitiveType.PrimitiveTypeName.INT32 => creader.getInteger
case PrimitiveType.PrimitiveTypeName.INT64 => creader.getLong
case PrimitiveType.PrimitiveTypeName.INT96 => new String(creader.getBinary.getBytes)
case PrimitiveType.PrimitiveTypeName.FIXED_LEN_BYTE_ARRAY => new String(creader.getBinary.getBytes)
}
}
Question: However, the inner functions (e.g. creader.getBoolean, etc.) are (obviously) executed at the time of the match. How do I capture those functions as objects to execute at a later time rather than having them execute when yld is assigned?
Context:
This is so that in a later for loop, I don't have to match again:
for (i <- 0L to 900000) {
println(yld)
}
Because my object creader is an iterator on column-stored data, being able to make the type decision only one time should be more efficient than having to make it every time, i.e.
for (i <- 0L to 900000) {
column.getType match {
case PrimitiveType.PrimitiveTypeName.BINARY => println(new String(creader.getBinary.getBytes))
case PrimitiveType.PrimitiveTypeName.BOOLEAN => println(creader.getBoolean)
case PrimitiveType.PrimitiveTypeName.DOUBLE => println(creader.getDouble)
case PrimitiveType.PrimitiveTypeName.FLOAT => println(creader.getFloat)
case PrimitiveType.PrimitiveTypeName.INT32 => println(creader.getInteger)
case PrimitiveType.PrimitiveTypeName.INT64 => println(creader.getLong)
case PrimitiveType.PrimitiveTypeName.INT96 => println(new String(creader.getBinary.getBytes))
case PrimitiveType.PrimitiveTypeName.FIXED_LEN_BYTE_ARRAY => println(new String(creader.getBinary.getBytes))
}
}
If you have a method def foo = 42 you can convert it to a function and assign it to a val by val func = foo _.

Pattern Matching Pass Through in Scala

I want to do something like this:
val a = v match {
case 1 => 1
case 2 if (condition) => logging
case 2 if (other conditions) => 3
case 2 if (more conditions) => 4
case _ => 5
}
I want this to return just log for first case 2, but fall through otherwise to see what gets returned
edit: updated
Scala's case matching doesn't "fall through", but if I understand correctly, this will do what you want.
val a = v match {
case 1 => 1
case 2 => {
logging // I'm assuming `logging` is some Unit
if(some condition) 3
else if(some other condition) 4
else 5
}
case _ => 5
}
Something like this?
If v == 2, a will be assigned logging otherwise a will be assigned the value of v
val a = v match {
case 2 => logging
case _ => v
}