Can Scala Option class be used as a function argument? - scala

I have a recursive function which collects the leaf nodes of a kd-tree. This function has to take KdNode as an argument. The KdNode has the following class definition:
case class KdNode(value: (Double, Double), left: Option[KdNode], right: Option[KdNode], axis: Int, BB_A:BoundingBox, BB_B:BoundingBox)
The function definition where it is taken as an argument is:
def collectLeafNodes(t:KdNode): List[BoundingBox] = {
if(t == None) return
if (t.left == None && t.right == None) {
Some(listBoundingBox.::(t.BB_A,t.BB_B))
return
}
collectLeafNodes(t.left)
collectLeafNodes(t.right)}
Here, I encounter error on the last 2 lines saying: "Type mismatch, expected: KdNode, actual: Option[KdNode].
I am calling this function by building the kd-tree in variable "tree" and giving it as an argument:
val listofBoundingBoxes=collectLeafNodes(tree)
What is a possible workaround in this situation? In addition, I think there should be a way to pass the root node instead of tree to the collectLeafNodes function, is that possible given the tree is built in a separate function.
Thanks.

You ask, in the comments, how it can be done without return. Here's one way.
def collectLeafNodes(t :KdNode) :List[BoundingBox] =
List(t.BB_A, t.BB_B) :::
t.left.fold(List.empty[BoundingBox])(collectLeafNodes) :::
t.right.fold(List.empty[BoundingBox])(collectLeafNodes)
The result, without return, is the concatenation of 3 lists:
Since t is a KdNode and not an Option[KdNode], we know that the the BB values are real. That's the 1st List.
If t.left is None then the 2nd List is empty, otherwise the 2nd List is whatever the recursive call to collectLeafNodes(t.left) returns. (The argument is automatically supplied so it need not be specified.)
Same for the 3rd List with t.right
corrected for leaf nodes only
def collectLeafNodes(t :KdNode) :List[BoundingBox] = {
if (t.left.isEmpty && t.right.isEmpty) List(t.BB_A, t.BB_B)
else t.left .fold(List.empty[BoundingBox])(collectLeafNodes) :::
t.right.fold(List.empty[BoundingBox])(collectLeafNodes)
}

You can map over the option object:
val res: List[BoundingBox] = t.left.map(collectLeafNodes).getOrElse(List())

Because t.right is type of Option and not type of Kdnode.
You can unwrap Option to solve this e.g.
collectLeafNodes(t.right.get)}
collectLeafNodes(t.right.orElse(None)}
Hope this helps

Related

Write a Scala Programs to find even numbers and a number just before it

I written the code below for finding even numbers and the number just before it in a RDD object. In this I first converted that to a List and tried to use my own function to find the even numbers and the numbers just before them. The following is my code. In this I have made an empty list in which I am trying to append the numbers one by one.
object EvenandOdd
{
def mydef(nums:Iterator[Int]):Iterator[Int]=
{
val mylist=nums.toList
val len= mylist.size
var elist=List()
var i:Int=0
var flag=0
while(flag!=1)
{
if(mylist(i)%2==0)
{
elist.++=List(mylist(i))
elist.++=List(mylist(i-1))
}
if(i==len-1)
{
flag=1
}
i=i+1
}
}
def main(args:Array[String])
{
val myrdd=sc.parallelize(List(1,2,3,4,5,6,7,8,9,10),2)
val myx=myrdd.mapPartitions(mydef)
myx.collect
}
}
I am not able to execute this command in Scala shell as well as in Eclipse and not able to figure out the error as I am just a beginner to Scala.
The following are the errors I got in Scala Shell.
<console>:35: error: value ++= is not a member of List[Nothing]
elist.++=List(mylist(i))
^
<console>:36: error: value ++= is not a member of List[Nothing]
elist.++=List(mylist(i-1))
^
<console>:31: error: type mismatch;
found : Unit
required: Iterator[Int]
while(flag!=1)
^
Your code looks too complicated and not functional. Also, it introduce potential problems with memory: you take Iterator as param and return Iterator as output. So, knowing that Iterator itself could be lazy and has under the hood huge amount of data, materializing it inside method with list could cause OOM. So your task is to get as much data from initial iterator as it it enough to answer two methods for new Iterator: hasNext and next
For example (based on your implementation, which outputs duplicates in case of sequence of even numbers) it could be:
def mydef(nums:Iterator[Int]): Iterator[Int] = {
var before: Option[Int] = None
val helperIterator = new Iterator[(Option[Int], Int)] {
override def hasNext: Boolean = nums.hasNext
override def next(): (Option[Int], Int) = {
val result = (before, nums.next())
before = Some(result._2)
result
}
}
helperIterator.withFilter(_._2 % 2 == 0).flatMap{
case (None, next) => Iterator(next)
case (Some(prev), next) => Iterator(prev, next)
}
}
Here you have two iterators. One helper, which just prepare data, providing previous element for each next. And next on - resulting, based on helper, which filter only even for sequence elements (second in pair), and output both when required (or just one, if first element in sequence is even)
For initial code
Additionally to answer of #pedrorijo91, in initial code you do did not also return anything (suppose you wanted to convert elist to Iterator)
It will be easier if you use a functional coding style rather than an iterative coding style. In functional style the basic operation is straightforward.
Given a list of numbers, the following code will find all the even numbers and the values that precede them:
nums.sliding(2,1).filter(_(1) % 2 == 0)
The sliding operation creates a list containing all possible pairs of adjacent values in the original list.
The filter operation takes only those pairs where the second value is even.
The result is an Iterator[List[Int]] where each List[Int] has two elements. You should be able to use this in your RDD framework.
It's marked part of the developer API, so there's no guarantee it'll stick around, but the RDDFunctions object actually defines sliding for RDDs. You will have to make sure it sees elements in the order you want.
But this becomes something like
rdd.sliding(2).filter(x => x(1) % 2 == 0) # pairs of (preceding number, even number)
for the first 2 errors:
there's no ++= operator on Lists. You will have to do list = list ++ element

Exception handling in Scala functional programming

I am going through Functional Programming In Scala ( Author :Paul Chiusano and Runar Bjarnarson), found below explanation for not using below total function for exception handling . It says if we are doing a lager computation we should not use, what exactly mean by it . Will you please explain giving a simple example . Thanks !!
Use types to communicate error cases rather than values
Lets a program called Foo is using the function mean. Unfortunately lets an empty IndexedSeq is sent as the argument to the mean function. In that case mean function would return onEmpty which is a Double.
Because mean returns a double when IndexedSeq is empty, the caller program (Foo program) cannot differentiate between the normal case (where the list is non empty) and the undefined case (where list is empty).
The problem with the mean function it returns Double in both undefined case and the normal case when list is non empty.
val someList = List.empty[Double]
val meanValue = mean(someList, -1)
if (meanValue == - 1) //undefined case else meanValue
The above way of checking the undefined value of the function mean is not recommended.
Author wants to communicate the undefined state by using some type.
Here is how we can do that
def mean(list: List[Double]): Option[Double] = {
if (list.isEmpty) None
else Some(list.sum / list.length)
}
The above mean function will return None when undefined case is encountered (list is empty) and does not rely on the unsafe communication of returning a value.
Foo program might stop computing when an undefined is return the mean function or Foo program might take a different branch when encounter by the undefined value (value returned by the mean function when list is empty). But Foo program has to reply on onEmpty value to check for the undefined case.
Imagine your program can receive a list List(-2.0, 0.0).
val list = List(-2.0, 0.0)
val theMean = mean(list, -1.0)
// now I want to handle the error case
if (theMean == -1.0)
println("mean can't be computed!") // wrong!
If mean would not take some silly default value but would return an Option[Double] or an Either[String,Double] or... it is no longer possible to make such a mistake.

How do I return a value from a scala function?

I am fairly new to scala and was trying out a few simple things. I created a function that looks something like this:
private def checkValu() : Option[Integer] = {
if(!list.isEmpty()){
for(value <-list){
val x = list.get(0)
}
}
return (x)
}
I call the function in order to return the value x.I access the value of the list and want to return the first value in the list. But somehow this does not seem to work. It gives me an error saying
"not found value x".
I also tried doing without the "return" statment, but then it gives me errors at the if and for loop saying
"type mismatch; found : Unit required: Option[Integer]"
What am I missing here? Could seombody please help me here.
Thank you in advance.
I guess you are looking for something like this:
def checkValue() : Option[Integer] = {
if(!list.isEmpty()) {//Assuming list is java.util.List[Integer] and want the last value
return Some(list.get(list.size() - 1))
}
None
}
This solution uses java.util.List<Integer>, I guess you used that for list. None is simply returned when no values are present, otherwise, the last, though I was not sure that was your intention, in case you want the first: return Some(list.get(0))
A more idiomatic solution:
def checkValue() : Option[Integer] = {
if(!list.isEmpty()) {//Assuming list is java.util.List[Integer] and first value is required
Some(list.get(0))
} else {
None
}
}
I was unsure which value you wanted to return because you wanted to loop through the whole list (naming of the method did not help either). Probably #cmbaxter was right and you wanted the first one.
Just some notes about the error messages: first: you were referring to a variable x that was out of scope (outside of the for comprehension), so it was not a good choice. The second one was probably caused by because of the if statement without else, which results in Unit. As that remain the only expression, that was tried to be returned, though that was not an Option[Integer].
Wouldn't this be easier:
def checkValue(): Option[Int] = list.headOption
// assuming list is List[Int] and you want to return option of the first element

Value :: is not a member of type parameter [T] Scala?

For a lister class that I have to make, which is basically just a list with some extra methods I have to have an intersection method. I think what I have below works but at the part that I labeled problem line I keep getting a "value :: is not a member of type parameter S" error. What would be causing this? Second part is just bonus but if anyone could say why what I labeled problem line two keeps saying ambiguous refrence to overloaded definition that would be great. There are two constructors, one which takes one element and starts the list, which is public, and a private main constructor that can take a list of type s and make a lister.
def intersec(other:List[S]) = {
val a=this.toList
val b=other.toList
var holder = List()
var counter=b.length
if (b.length<a.length)cycles=a.length
for (i<-0 to cycles){
if (a.contains(b(i))){
holder=holder::b(i) // problem line
}
new Lister(holder) // problem line 2
}}
b(i) has type S and of course type S does not have prepend function. Notice that :: is right associative. So holder :: b(i) means that you are calling :: function of b(i) with parameter holder.
So you need to change that line to: holder = b(i) :: holder
By the way, your code is quite imperative and suffers from lack of being declarative. I think you want to have an intersect function with different behaviour than the Scala standard library intersect function. In this case, you may use implicit class to extend the List to have new function.

How to know if a List is homogeneous

I want to know if a List is homogeneous.
Here is my code :
def isHomogeneous(ls: List[Any]) = ls.map(_.getClass).toSet.size == 1
Is there a better way ?
def allEqual(xs: Traversable[_]) =
xs.headOption.forall(head => xs.forall(_ == head))
def isHomogeneous(xs: Traversable[_]) =
allEqual(xs.view.map(_.getClass))
Keeps the getClass business separate from the traversal.
Uses more general type Traversable instead of List.
Works for Nil.
Does not traverse the entire collection unless necessary.
How about
def isHomogeneous(l: List[Any]) = {
val t = l(0).getClass
l.forall(_.getClass == t)
}
So if all elements have the same type as the first, it returns true
EDIT: To expand a bit on why I think this solution is better:
It only loops through the list once
It can exit early(If the second element is of a different class, it can immediately exit instead of trying other elements)
It does not create intermediate objects
It does not require a hashCode method to be implemented (Which it may, depending on the implementation of Set)
It looks, at least to me, clearer