Reputation: 53786
Using below code I'm attempting to produce
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 is 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)) }
is causing 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] one error found [error] (compile:compileIncremental) Compilation failed [error] Total time: 2 s, completed 11-Jun-2017 22:51:46
Am I not using map
correctly?
Upvotes: 3
Views: 2085
Reputation: 12794
The problem you are facing comes from the anonymous function you are trying to integrate a new tuple into your map; what you do is:
{ (m, s) => (m, List(s)) }
Where m
is of type Map[Date, List[(String , Float)]]
and s
is of type Details
.
The (m, List(s))
syntax means that you are creating a pair composed of the map m
and a singleton list that contains s
.
What you want to achieve, instead, is to put the two items in s
as a new pair of m
, something that 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 happens here: you take the accumulator map m
and update it at every turn of the fold with s.date
as the key and then a value. The value is the previously held value for that key (m.get(s.date)
, to make sure we're not overwriting that key) or an empty list if there is still no value, prepended with the value that we are looking at right now while the fold traverses the collection.
This solves the issue, but as you may see, what you are doing is a widely known operation of grouping and the Scala Collection API already provides you the basic infrastructure to achieve your objective.
You can refactor your code like follows and obtain 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 see, I've used the groupBy
combinator with the parse
method of your formatter. This function however presents as values of the resulting grouping the whole item, while you only wanted parts of it (which is why I further used the mapValues
combinator).
If you are further interested into the ordering in which your map exposes your items, remember to use a map that enforces some kind of ordering (like a SortedMap
).
Upvotes: 1
Reputation: 51271
I think the objective 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)]]
Upvotes: 2
Reputation: 10882
Here is how to fix that 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 of fold
you need to return updated Map m
.
In order to do so you need to check if m
already contains s.date
. If yes, add new s.det
to the existent list value and put updated list back into the map.
If this is the first occurrence of s.date
, just create an empty list, put s.det
into it and then put list back to m
.
Note, that values of the resulting Map might be in reverse order (as i'm using cons (::
) operator, which is more efficient than append for List
. You can reverse resulting values using map.mapValues(_.reverse)
).
Upvotes: 2
Reputation: 7768
This is not an exception but a compilation error. The error explains what's wrong with your code:
The second argument of foldLeft
(pointed by the ^
in the error message) must be a function (B, A) ⇒ B
. Your code has a (B, A) ⇒ (B, A)
instead...
Upvotes: 3