Transform values of a Map in groovy - groovy

Lets say I have a map Map<String, List<Integer>>.
I want to transform this map into Map<String, Map<Integer, Object>> by applying convert() method for each pair of key and element of nested list.
Object convert(String key, Integer value)
How can I achieve that?
I tried something like this:
map.collect { key, list ->
key: list.collectEntries {
[(element): convert(key, element)]
}
}
but I'm getting ClassCastException: ArrayList cannot be cast to Map.

Not at a computer, but try
map.collectEntries { key, list ->
[key, list.collectEntries { element ->
[element, convert(key, element)]
}]
}

You can simplify it a little:
def convert = { it -> it + 1 };
Map<String, List<Integer>> map = [foo: [1, 2, 3], bar: [4, 5, 6]];
map.collectEntries { k, v -> [(k): v.collect { convert(it) }] }

Related

Groovy iterate over Map of maps

I have a groovy map which looks like below.
image_map = [:]
image_map = [obj_1: ['1','2'], obj_2: ['3','4']]
I want to iterate through all the values(for obj_1, iterate throuth the list values['1','2']) for each object and run a method from the object.
obj_1.method(1)
obj_1.method(2)
obj_2.method(3)
obj_2.method(4)
Depends why you want to do it, but you could grab the values and flatten them:
image_map.values().flatten().each {
println it
}
So with the added requirement in the comment, you could do:
image_map.collectMany { k, v -> v.collect { "${k}.method($it)" } }
.each { println it }
To print
obj_1.method(1)
obj_1.method(2)
obj_2.method(3)
obj_2.method(4)
Edit 2 with another requirement... Assuming the keys ARE the objects (and not strings):
def obj_1 = [method: { it -> "I am obj1 $it" }]
def obj_2 = [method: { it -> "I am obj2 $it" }]
image_map = [(obj_1): ['1','2'], (obj_2): ['3','4']]
image_map.collectMany { k, v -> v.collect { [object: k, param: it] } }
.each { println it.object.method(it.param) }
Prints:
I am obj1 1
I am obj1 2
I am obj2 3
I am obj2 4

How can I create a map from object properties?

I get an object via some 3rd party api. I use a wrapper function to get it and then return a map from its properties:
wrapperFunc() {
def myObj = someapi.getblah().getSomeObect()
return [
aaa: myObj.aaa,
bbb: myObj.bbb,
ccc: myObj.ccc
]
}
Now I could manually go through EVERY property in the object like this, but is there an elegant groovy feature to dynamically build a map from the object's properties?
You could do something like this:
class Widget {
int width
int height
static void main(args) {
def obj = new Widget(width: 7, height: 9)
List<MetaProperty> metaProperties = obj.metaClass.properties
def props = [:]
for(MetaProperty mp : metaProperties) {
props[mp.name] = mp.getProperty(obj)
}
// props will look like [width:7, class:class demo.Widget, height:9]
}
}
This is basically a variant of #jeff-scott-brown's answer.
First, create a class that contains the Object-to-Map logic that uses the Groovy MetaClass to access a type's properties. findAll filters out the "class" property, which I assume you don't care about. The collectEntries line transforms each MetaProperty object into a Map entry.
class ElegantGroovyFeature {
static Map asType(Object o, Class m) {
if (m == Map) {
o.metaClass.properties
.findAll { it.getSetter() != null }
.collectEntries { prop -> [prop.name, prop.getProperty(o)] }
} else {
o.asType(m)
}
}
}
The extension class overrides the asType method, which corresponds to the as operator, enabling you to convert arbitrary objects to Maps using obj as Map expressions:
def obj = someapi.getBlah().getSomeObject()
use (ElegantGroovyFeature) {
def mapOfProperties = obj as Map
}
const obj = { foo: 'bar', baz: 42 };
const map = new Map(Object.entries(obj));
console.log(map); // Map { foo: "bar", baenter code herez: 42 }

Usage of parentheses in Groovy method call

I started learning Groovy, and understood that parentheses are optional in method calls, so
def list = [0, 1, 2, 3]
list.each ({ item ->
println "Item: $item"
})
is the same as
def list = [0, 1, 2, 3]
list.each { item ->
println "Item: $item"
}
But now found this example
def list = [0, 1, 2, 3]
list.each() { item ->
println "Item: $item"
}
which also works. How is it possible to first call method with empty parameter list, and then specify closure after it?
Things are a little different when closures are involved. There is a special facility for closures that occur as the last parameter (as explained here).
As another illustration, consider:
class Foo {
int bar(s, c) {
return c(s)
}
int abc(c, s) {
return c(s)
}
}
def foo = new Foo()
def s = "fox"
This is a classic style:
assert 3 == foo.bar(s, { it.size() })
Yet this will work for closures as last argument:
assert 3 == foo.bar(s) { it.size() }
This is classic:
assert 3 == foo.abc({ it.size() }, s)
But this won't work
// assert 3 == foo.abc({ it.size() }) s
No doubt the reasoning is that if there is only one parameter, as with List.each(), then the syntax is very elegant:
list.each { item -> println item }

groovy inject map with other map

Map<Integer, Map<String, String>> Actions = new HashMap<Integer, Map<String, String>>();
Map<Integer, List<ActionName>> actionList = Service.getAvailableActionsById(order.id, user.id)
for(Map.Entry<Integer, List<ActionName>> entry : actionList)
{
Map<String, String> actionMap = new HashMap<String, String>();
for(ActionName actionName: entry.getValue()){
actionMap.put(actionName.name(), actionName.name());
}
Actions.put(entry.getKey(), actionMap);
}
--==// For the same functionality above I want to use map inject, while doing as below it unable to inject all the list values to map
Map<Integer, List<ActionName>> actionList = [:]
if ( order.id) actionList = Service.getAvailableActionsById(order.id, session.user.id)
Map Actions = actionList.inject( [:] ) { map, id, values -> map.put( id, values ); return map; }
--=====
Map availableActions = actionList.inject( [:] ) { map, key, listValue ->
map << [ (key) : listValue.collectEntries { [ it.name(), it.name() ] } ]
}
This should give what you are looking for, but I do not get the rationale behind doing this.
inject's closure takes to arguments: result and current element. If you want to call inject() on a map you should treat each element as a Map.Entry:
actionList.inject( [:] ) { map, elem ->
map[ elem.key ] = elem.value // key -> id, value -> values
map
}

How to 'Slice' a Collection in Groovy

I have a collection of objects that I want to break up into a collection of collections, where each sequential group of 3 elements is in one collection.
For example, if I have
def l = [1,4,2,4,5,9]
I want to turn this into:
def r = [[1,4,2], [4,5,9]]
I'm doing it now by iterating over the collection and breaking it up.. but I then need to pass those 'groups' into a parallelized function that processes them.. It would be nice to eliminate this O(n) pre-processing work and just say something like
l.slice(3).collectParallel { subC -> process(subC) }
I've found the step method on the Range class, but it looks like that only acts on the indices. Any clever ideas?
Update:
I don't think this is a duplicate of the referenced link, although it's very close. As suggested below, it's more of the iterator-type thing I'm looking for.. the sub-collections will then be passed into a GPars collectParallel. Ideally I wouldn't need to allocate an entire new collection.
Check out groovy 1.8.6. There is a new collate method on List.
def list = [1, 2, 3, 4]
assert list.collate(4) == [[1, 2, 3, 4]] // gets you everything
assert list.collate(2) == [[1, 2], [3, 4]] //splits evenly
assert list.collate(3) == [[1, 2, 3], [4]] // won't split evenly, remainder in last list.
Take a look at the Groovy List documentation for more info because there are a couple of other params that give you some other options, including dropping the remainder.
As far as your parallel processing goes, you can cruise through the lists with gpars.
def list = [1, 2, 3, 4, 5]
GParsPool.withPool {
list.collate(2).eachParallel {
println it
}
}
If I understand you correctly, you're currently copying the elements from the original collection into the sub-collections. For more suggestions along those lines, checkout the answers to the following question: Split collection into sub collections in Groovy
It sounds like what you're instead looking for is a way for the sub-collections to effectively be a view into the original collection. If that's the case, check out the List.subList() method. You could either loop over the indices from 0 to size() in increments of 3 (or whatever slice size you choose) or you could get fancier and build an Iterable/List which would hide the details from the caller. Here's an implementation of the latter, inspired by Ted's answer.
class Slicer implements Iterator {
private List backingList
private int sliceSize
private int index
Slicer(List backingList, int sliceSize) {
this.backingList = backingList
this.sliceSize = sliceSize
}
Object next() {
if (!hasNext()) {
throw new NoSuchElementException()
}
def ret
if (index + sliceSize <= backingList.size()) {
ret = backingList.subList(index, index+sliceSize)
} else if (hasNext()) {
ret = backingList.subList(index, backingList.size())
}
index += sliceSize
return ret
}
boolean hasNext() {
return index < backingList.size()
}
void remove() {
throw new UnsupportedOperationException() //I'm lazy ;)
}
}
I like both solutions but here is a slightly improved version of the first solution that I like very much:
class Slicer implements Iterator {
private List backingList
private int sliceSize
private int index
Slicer(List backingList, int sliceSize) {
this.backingList = backingList;
int ss = sliceSize;
// negitive sliceSize = -N means, split the list into N equal (or near equal) pieces
if( sliceSize < 0) {
ss = -sliceSize;
ss = (int)((backingList.size()+ss-1)/ss);
}
this.sliceSize = ss
}
Object next() {
if (!hasNext()) {
throw new NoSuchElementException()
}
def ret = backingList.subList(index, Math.min(index+sliceSize , backingList.size()) );
index += sliceSize
return ret
}
boolean hasNext() {
return index < backingList.size() - 1
}
void remove() {
throw new UnsupportedOperationException() //I'm lazy ;)
}
List asList() {
this.collect { new ArrayList(it) }
}
List flatten() {
backingList.asImmutable()
}
}
// ======== TESTS
def a = [1,2,3,4,5,6,7,8];
assert [1,2,3,4,5,6,7,8] == a;
assert [[1, 2], [3, 4], [5, 6], [7, 8]] == new Slicer(a,2).asList();
assert [[1,2,3], [4,5,6], [7,8]] == (new Slicer(a,3)).collect { it } // alternative to asList but inner items are subList
assert [3, 2, 1, 6, 5, 4, 8, 7] == ((new Slicer(a,3)).collect { it.reverse() } ).flatten()
// show flatten iterator
//new Slicer(a,2).flattenEach { print it }
//println ""
// negetive slice into N pieces, in this example we split it into 2 pieces
assert [[1, 2, 3, 4], [5, 6, 7, 8]] == new Slicer(a,-2).collect { it as List } // same asList
assert [[1, 2, 3], [4, 5, 6], [7, 8]] == new Slicer(a,-3).asList()
//assert a == (new Slicer(a,3)).flattenCollect { it }
assert [9..10, 19..20, 29..30] == ( (new Slicer(1..30,2)).findAll { slice -> !(slice[1] % 10) } )
assert [[9, 10], [19, 20], [29, 30]] == ( (new Slicer(1..30,2)).findAll { slice -> !(slice[1] % 10) }.collect { it.flatten() } )
println( (new Slicer(1..30,2)).findAll { slice -> !(slice[1] % 10) } )
println( (new Slicer(1..30,2)).findAll { slice -> !(slice[1] % 10) }.collect { it.flatten() } )
There isn't anything built in to do exactly what you want, but if we #Delegate calls to the native lists's iterator, we can write our own class that works just like an Iterator that returns the chunks you're looking for:
class Slicer {
protected Integer sliceSize
#Delegate Iterator iterator
Slicer(objectWithIterator, Integer sliceSize) {
this.iterator = objectWithIterator.iterator()
this.sliceSize = sliceSize
}
Object next() {
List currentSlice = []
while(hasNext() && currentSlice.size() < sliceSize) {
currentSlice << this.iterator.next()
}
return currentSlice
}
}
assert [[1,4,2], [4,5,9]] == new Slicer([1,4,2,4,5,9], 3).collect { it }
Because it has all of the methods that a normal Iterator does, you get the groovy syntactic sugar methods for free with lazy evaluation on anything that has an iterator() method, like a range:
assert [5,6] == new Slicer(1..100, 2).find { slice -> slice.first() == 5 }
assert [[9, 10], [19, 20], [29, 30]] == new Slicer(1..30, 2).findAll { slice -> !(slice[1] % 10) }

Resources