Converting a list to a map with foldLeft

Using the code below I am trying to create

 Map(2017-06-03 09:25:30 -> List( ("c",2190.79) , ("d",24.11), ("d",24.11), ("d",24.11) ),
     2017-06-03 09:25:40 -> List( ("b",24.62) , ("b",24.62)) ,
     2017-06-03 09:25:50 -> List( ("a",194.55) , ("a",194.55)) )

      

from

val l = List("a,194.55,2017-06-03 09:25:50",
             "b,24.62,2017-06-03 09:25:40",
             "c,2190.79,2017-06-03 09:25:30",
             "d,24.11,2017-06-03 09:25:30",
             "a,194.55,2017-06-03 09:25:50",
             "b,24.62,2017-06-03 09:25:40",
             "c,2190.79,2017-06-03 09:25:30",
             "d,24.11,2017-06-03 09:25:30")

      

Here's the complete code:

object Main extends App {

    val l = List("a,194.55,2017-06-03 09:25:50",
                 "b,24.62,2017-06-03 09:25:40",
                 "c,2190.79,2017-06-03 09:25:30",
                 "d,24.11,2017-06-03 09:25:30",
                 "a,194.55,2017-06-03 09:25:50",
                 "b,24.62,2017-06-03 09:25:40",
                 "c,2190.79,2017-06-03 09:25:30",
                 "d,24.11,2017-06-03 09:25:30")

    case class Details(date : java.util.Date , det : (String , Float))

    val format = new java.text.SimpleDateFormat("yyyy-MM-dd hh:mm:ss")

    val p = l.map(m => new Details(format.parse(m.split(",")(2)), ( m.split(",")(0),m.split(",")(1).toFloat) ))

    val s = p.sortBy(r => (r.date))

val map = s.foldLeft(Map[java.util.Date, List[(String , Float)]]()) { (m, s) => (m , List(s)) }

}

      

Line:

val map = s.foldLeft(Map[java.util.Date, List[(String , Float)]]()) { (m, s) => (m , List(s)) }

      

raises the following compilation error:

[error] found: (scala.collection.immutable.Map [java.util.Date, List [(String, Float)]], List [Main.Details]) [error] required: scala.collection.immutable.Map [ java.util.Date, List [(String, Float)]] [error] val map = s.foldLeft (Mapjava.util.Date, List [(String, Float)]) {(m, s) => (m , List (s))} [error]
^ [error] encountered one error [error] (compilation: compileIncremental) Compilation error [error] Total time: 2s, completed 11-Jun-2017 22:51:46

Am I not using it correctly map

?

+3


source to share


4 answers


The problem you are having is with the anonymous function that you are trying to integrate with a new tuple in your map; what are you doing:

{ (m, s) => (m, List(s)) }

      

Where m

has a type Map[Date, List[(String , Float)]]

and s

has a type Details

.

The syntax (m, List(s))

means that you are creating a pair consisting of a map m

and a singleton list containing s

.

Instead, you have to put two elements in s

a new pair m

, which you can achieve by doing the following:

{ (m, s) => m.updated(s.date, s.det :: m.get(s.date).getOrElse(List.empty)) }

      



Let's see what's going on here: You take the battery map m

and update it with each turn with s.date

a key followed by a value. The value is the previously stored value for this key ( m.get(s.date)

to make sure we don't overwrite this key) or an empty list, if the value is still missing, the value we are looking at is added while fold moves the collection.

This solves the problem, but as you can see, what you are doing is a well-known grouping operation and the Scala API Collection already provides you with the underlying infrastructure to accomplish your goal.

You can refactor your code like this and get the same result:

object Main extends App {

  val l = List("a,194.55,2017-06-03 09:25:50",
    "b,24.62,2017-06-03 09:25:40",
    "c,2190.79,2017-06-03 09:25:30",
    "d,24.11,2017-06-03 09:25:30",
    "a,194.55,2017-06-03 09:25:50",
    "b,24.62,2017-06-03 09:25:40",
    "c,2190.79,2017-06-03 09:25:30",
    "d,24.11,2017-06-03 09:25:30")

  val format = new java.text.SimpleDateFormat("yyyy-MM-dd hh:mm:ss")

  val map = 
    l.groupBy(m => format.parse(m.split(",")(2))).
      mapValues(l => l.map(m => (m.split(",")(0),m.split(",")(1).toFloat)))

}

      

As you can see, I used a combinator groupBy

with parse

your formatting method . However, this function represents the final grouping values ​​of the entire element, while you only need parts of it (which is why I used the combinator mapValues

).

If you are more interested in the order in which your card displays your objects, be sure to use a card that provides some order (for example SortedMap

).

+1


source


This is not an exception, but a compilation error. The error explains what is wrong with your code:



The second argument foldLeft

(indicated ^

in the error message) must be a function (B, A) β‡’ B

. Instead, your code has (B, A) β‡’ (B, A)

...

+3


source


Here's how to fix this line:

val map = s.foldLeft(Map[java.util.Date, List[(String , Float)]]()) {
  (m, s) =>
    m +
      (s.date ->
        (s.det :: m.getOrElse(s.date, List[(String , Float)]()))
      )
}

      

For each iteration, fold

you need to return an updated map m

.

To do this, you need to check if it contains m

s.date

. If yes, add a new one s.det

to the value of the existing list and put the updated list back on the map.

If this is the first occurrence s.date

, just create an empty list, put s.det

in it and then return the list m

.

Note that the values ​​of the resulting Map can be in reverse order (since I am using cons ( ::

), which is more efficient than append for List

. You can reverse the resulting values ​​with map.mapValues(_.reverse)

).

+2


source


I think the goal can be achieved a little more directly.

val format = new java.text.SimpleDateFormat("yyyy-MM-dd hh:mm:ss")

l.map(_.split(","))
 .groupBy(a => format.parse(a(2)))
 .mapValues(_.map(a => (a(0),a(1).toFloat))) //Map[java.util.Date,List[(String, Float)]]

      

+2


source







All Articles