From the simple R example of reshape here, given a List of Maps like this:
data = [ [ id: 1, time: 1, x1: 5, x2: 6 ],
[ id: 1, time: 2, x1: 3, x2: 5 ],
[ id: 2, time: 1, x1: 6, x2: 1 ],
[ id: 2, time: 2, x1: 2, x2: 4 ] ]
And the methods melt
:
List melt( List data, List keys ) {
data.collectMany {
it.subMap( keys ).with { k ->
( it - k ).inject( [] ) { r, v ->
r << ( k + [ key:v.key, value:v.value ] )
}
}
}
}
and cast
:
List cast( List data, String subject, Closure fn ) {
data.groupBy( { it[ subject ] } ).collect { k, v ->
v.groupBy( { it[ 'key' ] } ).collectEntries { k2, v2 ->
fn( v2.value ).with { f ->
[ (subject): k, (k2): f ]
}
}
}
}
We can first melt
our data with:
def a = melt( data, [ 'id', 'time' ] )
Which gives us the List of Maps:
[ [ id:1, time:1, key:x1, value:5 ],
[ id:1, time:1, key:x2, value:6 ],
[ id:1, time:2, key:x1, value:3 ],
[ id:1, time:2, key:x2, value:5 ],
[ id:2, time:1, key:x1, value:6 ],
[ id:2, time:1, key:x2, value:1 ],
[ id:2, time:2, key:x1, value:2 ],
[ id:2, time:2, key:x2, value:4 ] ]
We can then get the mean value of x1
and x2
by id
using:
/*
[ [ id:1, x1:4, x2:5.5 ],
[ id:2, x1:4, x2:2.5 ] ]
*/
def avgById = cast( a, 'id' ) {
it.sum() / it.size()
}
Or by time
by:
/*
[ [ time:1, x1:5.5, x2:3.5 ],
[ time:2, x1:2.5, x2:4.5 ] ]
*/
def avgByTime = cast( a, 'time' ) {
it.sum() / it.size()
}
This is obviously a first pass, only taking the simplest of examples of what
reshape
can do. Much more work required