Scala case class, conditional Copy - scala

I've defined a case class and a value:
scala> case class N(a:Int, b:Int)
defined class N
scala> val nnn = N(2,3)
nnn: N = N(2,3)
I would like to modify a field based on an optional value, t1 and t2 with type Option[Int], this is what i did:
val nnn1 = t1.map( x => nnn.copy( a = x)).getOrElse(nnn)
val nnn2 = t2.map( x => nnn1.copy( b = x)).getOrElse(nnn1)
Theres a Lens/Monocle/Scalaz way to do it generic?

A good approach colud be
def someF(i:Int) = // a great computation with i :)
val na = t1.map(someF).getOrElse(nnn.a)
val newnnn = nnn.copy(a = na, b = t2.getOrElse(nnn.b))
In a case where you have to apply someF to t1 is probably a good idea separate it.
No lens for you.

Related

How to create custom operators with precedence

I hava a class with custom Operators
case class Num(var value:Int) {
def add(x:Num) = Num(value + x.value)
def mul(x:Num) = Num(value * x.value)
}
So I can call them like this
val a = Num(2)
val b = Num(3)
val c = Num(4)
val m1 = a add b mul c
But how can I execute mul before add? I saw a solution like +| instead of add, but I want include letters in my Operator and +add and *mul not working. Also I want to include a pow function, so this needs an higher precidence than mul
You can use Parenthesis after add.
val m1 = a add (b mul c) = 14
val m1 = a add b mul c = 20
Update
you do not have any restrictions in naming your methods. For example, you can define methods +, -, * and etc. for a class.
case class Num(var value:Int) {
def + (x:Num) = Num(value + x.value)
def *(x:Num) = Num(value * x.value)
}
object Num extends App {
val a = Num(2)
val b = Num(3)
val c = Num(4)
val m1 = a + b * c
println(m1)
}
Output
Num(14)

Scala how to avoid var during some override condition

Functional programming style of coding guideline says we should not use null or var in Scala for better functional programming code.
I want to perform some operation like below
var a = 2
if(condition==true){
a = a * 3 /*someOperation*/
}
if(condition2==true){
a = a * 6 /*someOperation*/
}
if(condition3==true){
a = a * 8 /*someOperation*/
}
val b = a * 2/*someOperation*/
So now how to avoid var in this condition and replace it with val?
The simplest way to avoid var with multiple conditions is to use temporary values
val a1 = 2
val a2 = if (condition) a1*3 else a1
val a3 = if (condition2) a2*6 else a2
val a = if (condition3) a3*8 else a3
val b = a * 2/*someOperation*/
In the real code you would give a1, a2, and a3 meaningful names to describe the result of each stage of processing.
If you are bothered about having these extra values in scope, put it in a block:
val a = {
val a1 = 2
val a2 = if (condition) a1*3 else a1
val a3 = if (condition2) a2*6 else a2
if (condition3) a3*8 else a3
}
Update
If you want a more functional approach, collect the conditions and modifications together and apply them in turn, like this:
val mods: List[(Boolean, Int=>Int)] = List(
(condition, _*3),
(condition2, _*6),
(condition3, _*8)
)
val a = mods.foldLeft(2){ case (a,(cond, mod)) => if (cond) mod(a) else a }
This is really only appropriate when either the conditions or the modifications are more complex, and keeping them together makes the code clearer.
val a = 2 * (if (condition) 3 else 1)
val b = 2 * a
Or, perhaps...
val a = 2
val b = 2 * (if (condition) a*3 else a)
It depends on if/how a is used after these operations.
I think you might have oversimplified your example, because we know the value of a when writing the code so you could just write it out like this:
val a = if (condition) 2 else 6
val b = a * 2
Assuming your real operation is more complex and can't be precalculated like that, then you might find a pattern match like this is a nicer way to do it:
val a = (condition, 2) match {
case (true, z) =>
z * 3
case (false, z) =>
z
}
val b = a * 2
You can try the following approach:
type Modification = Int => Int
type ModificationNo = Int
type Conditions = Map[ModificationNo, Boolean]
val modifications: List[(Modification, ModificationNo)] =
List[Modification](
a => a * 3,
a => a * 6,
a => a * 8
).zipWithIndex
def applyModifications(initial: Int, conditions: Conditions): Int =
modifications.foldLeft[Int](initial) {
case (currentA, (modificationFunc, modificationNo)) =>
if (conditions(modificationNo)) modificationFunc(currentA)
else currentA
}
val a: Int = applyModifications(initial = 2,
conditions = Map(0 -> true, 1 -> false, 2 -> true))
It may look complicated but this approach allows additional flexibility if number of conditions is big enough.
Now when you have to add more conditions, you don't need to write new if-statements and further reassignments to var. Just add a modification function to an existing list of
there is no 1 perfect solution.
sometimes it is ok to use var if it simplifies the code and limited in scope of a single function.
that being said, this is how I would do it in functional way:
val op1: Int => Int =
if (condition1) x => x * 3
else identity
val op2: Int => Int =
if (condition2) x => x * 6
else identity
val op3: Int => Int =
if (condition3) x => x * 8
else identity
val op = op1 andThen op2 andThen op3
// can also be written as
// val op = Seq(op1, op2, op3).reduceLeft(_ andThen _)
val a = 2
val b = op(a) * 2
The easiest way it to wrap your variable into a monad, so that you .map over it. The simplest monad is an Option, so you could write:
val result = Option(a).map {
case a if condition => a*2
case a => a
}.map {
case a if condition2 => a*6
case a => a
}.fold(a) {
case a if condition3 => a*8
case a => a
}
(The last operation is fold instead of map so that you end up with the "raw" value for the result, rather than an option. Equivalently, you could write it as a .map, and then add .getOrElse(a) at the end).
When you have many conditional operations like this, or many use cases where you have to repeat the pattern, it might help to put them into a list, and then traverse that list instead:
def applyConditionals[T](toApply: (() => Boolean, T => T)*) = toApply
.foldLeft(a) {
case (a, (cond, oper)) if cond() => oper(a)
case (a, _) => a
}
val result = applyConditionals[Int] (
(() => condition, _ * 2),
(() => condition2, _ * 6),
(() => condition3, _ * 8)
)
The important point is that FP is a whole new paradigm of programming. Its so fundamentally different that sometimes you can not take an excerpt of imperative code and try to convert it to functional code.
The difference applies not just to code but to the way of thinking towards solving a problem. Functional programming requires you to think in terms of chained mathematical computation which are more or less independent of each other (which means that each of these mathematical computation should not be changing anything outside of its own environment).
Functional programming totally avoids mutation of state. So, if your solution has a requirement to have a variable x which has a value 10 at one point and other value 100 at some other point... then your solution is not functional. And you can not write function code for a solution which is not functional.
Now, if you look at your case (assuming you do not actually need a to be 2 and then change to 6 after sometime) and try to convert it into chain of independent mathematical computation, then the simplest one is following,
val a = if (condition) 2 else 6
val b = a * 2

Scala Generic Type slow

I do need to create a method for comparison for either Int or String or Char. Using AnyVal was not make it possible as there were no method's for <, > comparison.
However Typing it into Ordered shows a significant slowness. Are there better ways to achieve this? The plan is to do a generic binary sorting, and found Generic typing decreases the performance.
def sample1[T <% Ordered[T]](x:T) = { x < (x) }
def sample2(x:Ordered[Int]) = { x < 1 }
def sample3(x:Int) = { x < 1 }
val start1 = System.nanoTime
sample1(5)
println(System.nanoTime - start1)
val start2 = System.nanoTime
sample2(5)
println(System.nanoTime - start2)
val start3 = System.nanoTime
sample3(5)
println(System.nanoTime - start3)
val start4 = System.nanoTime
sample3(5)
println(System.nanoTime - start4)
val start5 = System.nanoTime
sample2(5)
println(System.nanoTime - start5)
val start6 = System.nanoTime
sample1(5)
println(System.nanoTime - start6)
The results shows:
Sample1:696122
Sample2:45123
Sample3:13947
Sample3:5332
Sample2:194438
Sample1:497992
Am I doing the incorrect way of handling Generics? Or should I be doing the old Java method of using Comparator in this case, sample as in:
object C extends Comparator[Int] {
override def compare(a:Int, b:Int):Int = {
a - b
}
}
def sample4[T](a:T, b:T, x:Comparator[T]) {x.compare(a,b)}
The Scala equivalent of Java Comparator is Ordering. One of the main differences is that, if you don't provide one manually, a suitable Ordering can be injected implicitly by the compiler. By default, this will be done for Byte, Int, Float and other primitives, for any subclass of Ordered or Comparable, and for some other obvious cases.
Also, Ordering provides method definitions for all the main comparison methods as extension methods, so you can write the following:
import Ordering.Implicits._
def sample5[T : Ordering](a: T, b: T) = a < b
def run() = sample5(1, 2)
As of Scala 2.12, those extension operations (i.e., a < b) invoke wrapping in a temporary object Ordering#Ops, so the code will be slower than with a Comparator. Not much in most real cases, but still significant if you care about micro-optimisations.
But you can use an alternative syntax to define an implicit Ordering[T] parameter and invoke methods on the Ordering object directly.
Actually even the generated bytecode for the following two methods will be identical (except for the type of the third argument, and potentially the implementation of the respective compare methods):
def withOrdering[T](x: T, y: T)(implicit cmp: Ordering[T]) = {
cmp.compare(x, y) // also supports other methods, like `cmp.lt(x, y)`
}
def withComparator[T](x: T, y: T, cmp: Comparator[T]) = {
cmp.compare(x, y)
}
In practice the runtime on my machine is the same, when invoking these methods with Int arguments.
So, if you want to compare types generically in Scala, you should usually use Ordering.
Do not do micro-tests in such way if you want to get results somehow similar you will have in production env.
First of all you need to warm-up jvm. And after that do your test as average of many iterations. Also, you need to prevent possible jvm optimizations because of const data. E.g.
def sample1[T <% Ordered[T]](x:T) = { x < (x) }
def sample2(x:Ordered[Int]) = { x < 1 }
def sample3(x:Int) = { x < 1 }
val r = new Random()
def measure(f: => Unit): Long = {
val start1 = System.nanoTime
f
System.nanoTime - start1
}
val n = 1000000
(1 to n).map(_ => measure {val k = r.nextInt();sample1(k)})
(1 to n).map(_ => measure {val k = r.nextInt();sample2(k)})
(1 to n).map(_ => measure {val k = r.nextInt();sample3(k)})
val avg1 = (1 to n).map(_ => measure {val k = r.nextInt();sample1(k)}).sum / n
println(avg1)
val avg2 = (1 to n).map(_ => measure {val k = r.nextInt();sample2(k)}).sum / n
println(avg2)
val avg3 = (1 to n).map(_ => measure {val k = r.nextInt();sample3(k)}).sum / n
println(avg3)
I got results, which look more fare for me:
134
92
83
This book could give some light on performance tests.

Scala apply list of functions to a object

I have a lit of functions
val f1 = (x: Int) => x + 1
val f2 = (x: Int) => x + 2
val f3 = (x: Int) => x + 3
I have a single value:
val data = 5
I want to apply all the functions to the value and return single value. So
f3(f2(f1(data)))
And must return 11.
Now, if I have a seq of functions:
val funcs = Seq(f1, f2, f3)
How can I get 11 from applying all the functions to the data variable ? What is the scala-way to do that ?
yet another way to doing it using chain method in the Function helper object
Function.chain(funcs)(data)
What you are looking for is foldLeft. Indeed, for each function, you apply it to the previous result:
funcs.foldLeft(data){ (previousres, f) => f(previousres) }
you can use foldLeft:
val result = funcs.foldLeft(5)((acc,curr) => curr(acc) )
Basically, you are trying to achieve Function Composition here. So, you could use compose and andThen methods here as:
val data = 5
val funcs = Seq(f1, f2, f3)
//using compose
val result1 = funcs.reduce((a,b) => a.compose(b))(data)
//using andThen
val result2 = funcs.reduce((a,b) => a.andThen(b))(data)
Both result1 and result2 will be 11 in your example.
Please note that the way andThen and compose operate are different. You could see Functional Composition for more information.

Generate alphanumeric string

I need some test company-names, like "rnd_company_blah23haf9", "rnd_company_g356fhg57" etc.
Is it possible to do something like
import scala.util.Random
val company = s"rnd_company_${Random.alphanumeric take 10 ?????}"
provided someone can fill out ????? of course.
Use .mkString("") to create a String from the Stream :
scala> val company = s"rnd_company_${Random.alphanumeric take 10 mkString}"
company: String = rnd_company_BbesF0EY1o
You have an example here
scala> val x = Random.alphanumeric
x: scala.collection.immutable.Stream[Char] = Stream(Q, ?)
scala> x take 10 foreach println
Q
n
m
x
S
Q
R
e
P
B
So you can try this:
import scala.util.Random
val company = s"rnd_company_${(xx take 10).mkString}"
Something verbose than the above answers but this one helps you to constrain the alphabet:
def randomText(textLength: Int = 10, alphabet: List[Char] = ('a' to 'd').toList) = {
(1 to textLength).toList.map { charPos =>
val randomIndex = (Math.random() * alphabet.length).floor.toInt
alphabet(randomIndex)
}.mkString("")
}