Reputation: 455
I have a code that converts the following datatypes:
from: SortedMap[Long, SortedMap[String, Double]] to: SortedMap[String, Array[Double]]
Can anyone please explain how this code does the above manipulation?
val convertedDataWindow = dataWindow.values.foldLeft(SortedMap.empty[String, Array[Double]]) {
case (res0, map) =>
(res0 /: map) {
case (res1, (key, value)) =>
res1.updated(key, res1.getOrElse(key, Array.empty) :+ value)
}
}
Upvotes: 1
Views: 145
Reputation: 17431
Consider the inner function on its own first:
def something(res0: SortedMap[String, Array[Double]],
map: SortedMap[String, Double]) = (res0 /: map) {
case (res1, (key, value)) =>
res1.updated(key, res1.getOrElse(key, Array.empty) :+ value)
}
/:
is another name for foldLeft
, this is the same as
map.foldLeft(res0) { ...}
You know how foldLeft
works in general? It runs through the collection, using the given function to "merge" each value into the initial value in turn. So this starts with res0
, and for every (key, value)
in map
, we merge it into our working result using .updated
: we add a new entry to the map, with key key
and value res1.getOrElse(key, Array.empty) :+ value
. That is, if there's already an entry for this key, we add value
onto the end of it; otherwise, we make a new Array
containing just value
.
So putting all that together, what this function is doing is merging map
into res0
, by making new entries for any new keys, or putting the values onto the Array
for any existing keys.
Now, the full function is doing another foldLeft
; we could write it as:
dataWindow.values.foldLeft(SortedMap.empty)(something)
So what this is doing is starting from an empty map, and then for each of dataWindow.values
in turn, merging that into our working map.
(Of course when I talk about "merging", in reality everything is immutable and we're creating a new "working" map every time we go through the loop. But sometimes it's clearer to imagine a single, mutable "working" map res
)
Upvotes: 2