Search code examples
scalafunctional-programmingfoldleft

How to sum number of Ints and Number of Floats within a List - Scala


I need to calculate the number of integers and floats i have in a Map which is like Map[String, List[(Int, String, Float)]]

The data comes from reading a file - the data inside for example looks kinda like (however there is a few more Routes):

Cycle Route (City),1:City Centre :0.75f,2:Main Park :3.8f,3:Central Station:2.7f,4:Modern Art Museum,5:Garden Centre:2.4f,6:Music Centre:3.4f

The map is split so that the String is the name of the route and the List is the rest of the data.

I want it to calculate the number of 'checkpoints' per route and total distance of each route (which is the float) then print out e.g. Oor Wullie Route has 6 checkpoints and total distance of 18.45km

I am guessing I need to use a foldLeft however i am unsure how to do so?

Example of a simple fold i have done before but not sure how to apply one to above scenario?

val list1 = List.range(1,20)

def sum(ls:List[Int]):Int = {
  ls.foldLeft(0) { _ + _}
}

Solution

  • You could do this with a fold, but IMO it is unnecessary.

    You know the number of checkpoints by simply taking the size of the list (assuming each entry in the list is a checkpoint).

    To compute the total distance, you could do:

    def getDistance(list: List[(Int, String, Float)]): Float = 
      list
        .iterator // mapping the iterator to avoid building an intermediate List instance
        .map(_._3) // get the distance Float from the tuple
        .sum // built-in method for collections of Numeric elements (e.g. Float)
    

    And then get your printout like:

    def summarize(routes: Map[String, List[(Int, String, Float)]]): Unit =
      for { (name, stops) <- routes } {
        val numStops = stops.size
        val distance = getDistance(stops)
        println(s"$name has $numStops stops and total distance of $distance km")
      }
    

    If you really wanted to compute both numStops and distance via foldLeft, Luis's comment on your question is the way to do it.

    edit - per Luis's request, putting his comment in here and cleaning it up a bit:

    stops.foldLeft(0 -> 0.0f) { 
       // note: "acc" is short for "accumulated"
       case ((accCount, accDistance), (_, _, distance)) => 
         (accCount + 1) -> (accDistance + distance) 
    }