Andre Queen - 1 year ago 82
Scala Question

# Finding the average from a mapped list of int

I am trying to get the average from a mapped list of ints, then return that value to the user when requested.
Here is my current code with problems, what am I doing wrong? I have included my functionality to find the last element of a tail, that works.

``````// *******************************************************************************************************************
// application logic

// *******************************************************************************************************************
// UTILITY FUNCTIONS
//GETS THE DATA FROM THE DATA.TXT
def readFile(filename: String): Map[String, List[Int]] = {
processInput(Source.fromFile(filename).getLines)
}
def processInput(lines: Iterator[String]): Map[String, List[Int]] = {
Try {
lines.foldLeft(Map[String, List[Int]]()) { (acc, line) =>

val splitline = line.split(",").map(_.trim).toList
}
}.getOrElse {
println("Sorry, an exception happened.")
Map()
}
}

//functionality to find the last tail element
def findLast(list:List[Int]):Int = {
if(list.tail == Nil)
else
findLast(list.tail)
}

//Function to find the average
def average(list:List[Int]):Double =
list.foldLeft(0.0)(_+_) / list.foldLeft(0)((r,c)=>r+1)

//Show last element in the list, most current WORKS
def currentStockLevel (stock: String): (String, Int) = {
(stock, mapdata.get (stock).map(findLast(_)).getOrElse(0))
}

//Show last element in the list, most current DOES NOT WORK
def averageStockLevel (stock: String): (String, Int) = {
(stock, mapdata.get (stock).map(average(_)).getOrElse(0))
}
``````

my txt file

``````SK1, 9, 7, 2, 0, 7, 3, 7, 9, 1, 2, 8, 1, 9, 6, 5, 3, 2, 2, 7, 2, 8, 5, 4, 5, 1, 6, 5, 2, 4, 1
SK2, 0, 7, 6, 3, 3, 3, 1, 6, 9, 2, 9, 7, 8, 7, 3, 6, 3, 5, 5, 2, 9, 7, 3, 4, 6, 3, 4, 3, 4, 1
SK4, 2, 9, 5, 7, 0, 8, 6, 6, 7, 9, 0, 1, 3, 1, 6, 0, 0, 1, 3, 8, 5, 4, 0, 9, 7, 1, 4, 5, 2, 8
SK5, 2, 6, 8, 0, 3, 5, 5, 2, 5, 9, 4, 5, 3, 5, 7, 8, 8, 2, 5, 9, 3, 8, 6, 7, 8, 7, 4, 1, 2, 3
``````

The error that I am getting is that expression of type AnyVal does not conform to type Int

Your `averageStockLevel` function returns the average value as an `Int` (the return type is `(String, Int)`) whereas the calculation that is done in `average` returns a `Double`.

So you either need to convert the calculated `Double` to an `Int` within `averageStockLevel` (e.g. by doing `average(_).toInt`), or you can change the return type of `averageStockLevel` to `(String, Double)`. The latter variant is obviously the better one since you don't loose the precision of your average value.

``````def averageStockLevel (stock: String): (String, Double) = {
(stock, mapdata.get(stock).map(average).getOrElse(0.0))
}
``````

This works, but whether or not it's a good idea to return `0.0` in case of a missing key is for you to decide. Another possibility is to omit the `getOrElse` part and return an `Option[(String,Double)]`.

Apart from that, your code is quite complex. `findLast` and `average` can be defined much easier (it's not really worth it to create an own function for finding the last element, but for the sake of completeness...):

``````// will throw an exception for empty lists, but so does your current code
def findLast(list:List[Int]) = list.last

def average(list:List[Int]): Double = list.sum.toDouble / list.size
``````

Another idea is to replace `List` by `Vector`. For operations such as `.size` and `.last`, `List` needs linear time whereas `Vector` basically takes constant time.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download