whats the best way to convert from a list of objec...
# announcements
w
whats the best way to convert from a list of objects (think database results) to a nested object set. For instance a JDBC results set that used
GROUP BY day, status
which would give me a list with the same day more than once and the same status more than once which returned a list of
Copy code
data class DayStatusCount(val day:LocalDate, val status:Status, val count:Long)
If I wanted to convert to a
Map<LocalDate, Map<Status, Long>>
or anythings similar to that. I've been creating mutable maps.
Copy code
val rawData: MutableMap<LocalDate, Map<Status, Long> = HashMap()
        data.forEach {
            rawData
                    .getOrPut(it.day) { HashMap() }
                    .getOrPut(it.status) { HashMap() }
// More as per step
        }
Sorry thats not the real code. but anyway convert from a list with duplicates to nested sets.
u
Copy code
import java.time.LocalDate

data class DayStatusCount(val day: LocalDate, val status: String, val count: Long)


val rawData: MutableMap<LocalDate, Map<String, Long>> = HashMap()


val data = listOf(
        DayStatusCount(day = LocalDate.of(2001, 1, 1), status = "TODO", count = 1L),
        DayStatusCount(day = LocalDate.of(2001, 1, 1), status = "IN_PROGRESS", count = 2L),
        DayStatusCount(day = LocalDate.of(2001, 1, 2), status = "TODO", count = 1L),
        DayStatusCount(day = LocalDate.of(2001, 1, 3), status = "TODO", count = 1L),
        DayStatusCount(day = LocalDate.of(2001, 1, 4), status = "TODO", count = 1L)
)

val groupdData: Map<LocalDate, List<DayStatusCount>> = data.groupBy { it -> it.day }
do you just want to group by
data
? Like the above example?
r
You could try something like
Copy code
val mapped = results.groupBy { it.day }
    .mapValues { (_, value) ->
        value.groupBy(
            { it.status },
            { it.count }
        )
    }
w
@Ubi I was doing multiple levels of grouping.
r
If you're not crazy into all the functional stuff, maybe
Copy code
fun List<DayStatusCount>.group(): Map<LocalDate, Map<Status, List<Long>>> {
    val mapped = mutableMapOf<LocalDate, MutableMap<Status, MutableList<Long>>>()
    forEach {
        mapped.getOrPut(it.day) { mutableMapOf() }
            .getOrPut(it.status) { mutableListOf() } += it.count
    }
    return mapped
}
(This one will probably perform and scale better.)
w
Yeah thats similar to my initial approach. I find it hard to think in the functional stuff at times. except you use
mutableMapOf()
rather than
HashMap()
Also I like the array syntax you use. which I'm still getting my head around. Not array exactly more like associative array.
r
Agreed. Also always going for a "one-liner" tends towards non-readability and bad performance when taken too far.
w
Its not the one line I try to go for. but generally avoiding mutation.
but in this case its mutation during construction I can live with that.
r
I tend to stick to
mutableMapOf
unless I specifically need a
HashMap
. (Which isn't all that common, usually I just need a map.)
w
Java habits. only thing about mutableMapOf() when you have nothing there is no "Of" I'd prefer it called mutableMap() but thats just trivial.
r
Indeed, and if this is in a separate method, you can always return it as a
Map
instead of
MutableMap
to clean up the API for the user.
w
Thanks
r
As far as the
Of
suffix goes, if I'm not passing anything in, I usually have to add the generic types, so it still reads pretty well to me (in my head this reads as "mutable map of local date to (mutable map of status to long)")
u
How about:
Copy code
val mapped: Map<LocalDate, Map<String, Long>> = data.groupBy { it.day }
        .mapValues { (_, value) -> value.map { it.status to it.count } }
        .mapValues { (_, values) -> values.toMap() }
w
Looks good.