Simplifying nested ifs with multiple exit points in Scala? - scala

There has to be a better way to do this.. I'm testing for a ray-triangle intersection and my code looks something like this
if(some condition) fail
else {
...
if(some other condition) fail
else {
...
intersection
}
}
with many nested ifs. It's disgusting. I'm doing this not to use any return statements. Is there an alternate control structure I could use here to manage the various method exit points?

You could use for comprehension:
val result: Option[BasicIntersection] = for {
edge1 <- Some(vertices(1) - vertices(0))
edge2 = vertices(2) - vertices(0)
P = ray.v cross edge2
determinant = edge1 dot P
if !(determinant > -Utils.EPSILON && determinant < Utils.EPSILON)
inv_determinant = 1.0/determinant
T = ray.p - vertices(0)
u = (T dot P) * inv_determinant
if !(u < 0 || u > 1)
Q = T cross edge1
v = (ray.v dot Q) * inv_determinant
if !(v < 0 || u + v > 1)
t = (edge2 dot Q) * inv_determinant
if !(t < Utils.EPSILON)
hit = ray.p + ray.v*t
} yield
if (hasUV) {
val d0 = Math.abs((hit - vertices(0)).length)
val d1 = Math.abs((hit - vertices(1)).length)
val d2 = Math.abs((hit - vertices(2)).length)
val uvAvg = (uv(0)*d0 + uv(1)*d1 + uv(2)*d2) / (d0 + d1 + d2)
new BasicIntersection(hit, edge1 cross edge2, t, uvAvg)
} else {
new BasicIntersection(hit, edge1 cross edge2, t)
}
result.getOrElse(new BasicIntersection()) // Your failure case

Related

How to use string.split() without foreach()?

Write a program in Scala that reads an String from the keyboard and counts the number of characters, ignoring if its UpperCase or LowerCase
ex: Avocado
R: A = 2; v = 1; o = 2; c = 1; d = 2;
So, i tried to do it with two fors iterating over the string, and then a conditional to transform the character in the position (x) to Upper and compare with the character in the position (y) which is the same position... basically i'm transforming the same character so i can increment in the counter ex: Ava -> A = 2; v = 1;
But with this logic when i print the result it comes with:
ex: Avocado
R: A = 2; v = 1; o = 2; c = 1; a = 2; d = 1; o = 2;
its repeting the same character Upper or Lower in the result...
so my teacher asked us to resolve this using the split method and yield of Scala but i dunno how to use the split without forEach() that he doesnt allow us to use.
sorry for the bad english
object ex8 {
def main(args: Array[String]): Unit = {
println("Write a string")
var string = readLine()
var cont = 0
for (x <- 0 to string.length - 1) {
for (y <- 0 to string.length - 1) {
if (string.charAt(x).toUpper == string.charAt(y).toUpper)
cont += 1
}
print(string.charAt(x) + " = " + cont + "; ")
cont = 0
}
}
}
But with this logic when i print the result it comes with:
ex: Avocado
R: A = 2; V = 1; o = 2; c = 1; a = 2; d = 1; o = 2;
Scala 2.13 has added a very handy method to cover this sort of thing.
inputStr.groupMapReduce(_.toUpper)(_ => 1)(_+_)
.foreach{case (k,v) => println(s"$k = $v")}
//A = 2
//V = 1
//C = 1
//O = 2
//D = 1
It might be easier to group the individual elements of the String (i.e. a collection of Chars, made case-insensitive with toLower) to aggregate their corresponding size using groupBy/mapValues:
"Avocado".groupBy(_.toLower).mapValues(_.size)
// res1: scala.collection.immutable.Map[Char,Int] =
// Map(a -> 2, v -> 1, c -> 1, o -> 2, d -> 1)
Scala 2.11
Tried with classic word count approach of map => group => reduce
val exampleStr = "Avocado R"
exampleStr.
toLowerCase.
trim.
replaceAll(" +","").
toCharArray.map(x => (x,1)).groupBy(_._1).
map(x => (x._1,x._2.length))
Answer :
exampleStr: String = Avocado R
res3: scala.collection.immutable.Map[Char,Int] =
Map(a -> 2, v -> 1, c -> 1, r -> 1, o -> 2, d -> 1)

Running different objects in IDEA - Scala

I have 3 different objects that I've written in IDEA, labelled PartA, PartB, and PartC. However, when I attempt to run any of these objects, the only one that gives me the option to run is PartB. When I right click on the code for PartA and PartC, I have no option to run them. Only PartB has the option to run. What's going on here, and how can I fix it so I can run the different objects I have written?
Edit: Sorry, first time posting a question here. Here's the code I have written.
object PartB extends App {
def easter(Y:Int): Int = {
val N = Y - 1900
val A = N - (N/19) * 19
val B = (7 * A + 1) / 19
val C = 11 * A + 4 - B
val M = C - (C / 29) * 29
val Q = N / 4
val S = N + Q + 31 - M
val W = S - (S / 7) * 7
val DATE = 25 - M - W
return DATE
}
println("Enter a year: ")
val year = scala.io.StdIn.readInt()
val date = easter(year)
var easter_day : String = ""
if (date == 0) {
easter_day = "March, 31"
} else if (date < 0) {
easter_day = "March, " + (31 + year)
} else {
easter_day = "April, " + date
}
println("In " + year + ", Easter is on " + easter_day + ".")
}
////////////////////////////////////////////////////////////////////////////////
object PartC {
def ack(m:Int, n:Int) : Int = {
if (m == 0) {
return n + 1
} else if (n == 0) {
return ack(m - 1, 1)
} else {
return ack(m - 1, ack(m, n - 1))
}
}
println("Enter a value for m: ")
val m = scala.io.StdIn.readInt()
println("Enter a value for n: ")
val n = scala.io.StdIn.readInt()
println(ack(m, n))
}
PartB extends App, but PartC doesn't. Presumably PartA doesn't either.
The App trait can be used to quickly turn objects into executable programs... the whole class body becomes the “main method”.
So PartB defines a main method.

Extract coefficients from binomial expression entered as a string in Scala

I am trying to write a program that can find the roots of a quadratic equation using Scala. The input should be a quadratic equation in the form ax^2+bx+c (e.g: 5x^2+2x+3) as a string.
I managed to code the calculation of the roots but am having trouble extracting the coefficients from the input. Here's the code I wrote for extracting the coefficients so far:
def getCoef(poly: String) = {
var aT: String = ""
var bT: String = ""
var cT: String = ""
var x: Int = 2
for (i <- poly.length - 1 to 0) {
val t: String = poly(i).toString
if (x == 2) {
if (t forall Character.isDigit) aT = aT + t(i)
else if (t == "^") {i = i + 1; x = 1}
}
else if (x == 1) {
if (t forall Character.isDigit) bT = bT + t(i)
else if (t == "+" || t == "-") x = 0
}
else if (x == 0) {
if (t forall Character.isDigit) cT = cT + t(i)
}
val a: Int = aT.toInt
val b: Int = bT.toInt
val c: Int = cT.toInt
(a, b, c)
}
}
Simple solution with regex:
def getCoef(poly: String) = {
val polyPattern = """(\d+)x\^2\+(\d+)x\+(\d+)""".r
val matcher = polyPattern.findFirstMatchIn(poly).get
(matcher.group(1).toInt, matcher.group(2).toInt, matcher.group(3).toInt)
}
Does not handle all cases (e.g.: minus) and just throws an error if the input does not match the pattern, but it should get you going.

Merge for mergesort in scala

I'm migrating from Java to Scala and I am trying to come up with the procedure merge for mergesort algorithm. My solution:
def merge(src: Array[Int], dst: Array[Int], from: Int,
mid: Int, until: Int): Unit = {
/*
* Iteration of merge:
* i - index of src[from, mid)
* j - index of src[mid, until)
* k - index of dst[from, until)
*/
#tailrec
def loop(i: Int, j: Int, k: Int): Unit = {
if (k >= until) {
// end of recursive calls
} else if (i >= mid) {
dst(k) = src(j)
loop(i, j + 1, k + 1)
} else if (j >= until) {
dst(k) = src(j)
loop(i + 1, j, k + 1)
} else if (src(i) <= src(j)) {
dst(k) = src(i);
loop(i + 1, j, k + 1)
} else {
dst(k) = src(j)
loop(i, j + 1, k + 1)
}
}
loop(from, mid, from)
}
seems to work, but it seems to me that it is written in quite "imperative" style
(despite i have used recursion and no mutable variables except for the arrays, for which the side effect is intended). I want something like this:
/*
* this code is not working and at all does the wrong things
*/
for (i <- (from until mid); j <- (mid until until);
k <- (from until until) if <???>) yield dst(k) = src(<???>)
But i cant come up with the proper solution of such kind. Can you please help me?
Consider this:
val left = src.slice(from, mid).buffered
val right = src.slice(mid, until).buffered
(from until until) foreach { k =>
dst(k) = if(!left.hasNext) right.next
else if(!right.hasNext || left.head < right.head) left.next
else right.next
}

Need pointers for optimization of Merge Sort implementation in Scala

I have just started learning Scala and sideways I am doing some algorithms also. Below is an implementation of merge sort in Scala. I know it isn't very "scala" in nature, and some might even reckon that I have tried to write java in scala. I am not totally familiar with scala, i just know some basic syntax and i keep googling if i need something more. So please give me some pointers on to what can i do in this code to make it more functional and in accord with scala conventions and best practices. Please dont just give correct/optimized code, i will like to do it myself. Any suggestions are welcomed !
def mergeSort(list: Array[Int]): Array[Int] = {
val len = list.length
if (len == 1) list
else {
var x, y = new Array[Int](len / 2)
val z = new Array[Int](len)
Array.copy(list, 0, x, 0, len / 2)
Array.copy(list, len / 2, y, 0, len / 2)
x = mergeSort(x)
y = mergeSort(y)
var i, j = 0
for (k <- 0 until len) {
if (j >= y.length || (i < x.length && x(i) < y(j))) {
z(k) = x(i)
i = i + 1
} else {
z(k) = y(j)
j = j + 1
}
}
z
}
}
[EDIT]
This code works fine and I have assumed for now that input array will always be of even length.
UPDATE
Removed vars x and y
def mergeSort(list: Array[Int]): Array[Int] = {
val len = list.length
if (len == 1) list
else {
val z = new Array[Int](len)
val x = mergeSort(list.dropRight(len/2))
val y = mergeSort(list.drop(len/2))
var i, j = 0
for (k <- 0 until len) {
if (j >= y.length || (i < x.length && x(i) < y(j))) {
z(k) = x(i)
i = i + 1
} else {
z(k) = y(j)
j = j + 1
}
}
z
}
}
Removing the var x,y = ... would be a good start to being functional. Prefer immutability to mutable datasets.
HINT: a method swap that takes two values and returns them ordered using a predicate
Also consider removing the for loop(or comprehension).