Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Groovy Map of Lists into List of Maps

Tags:

list

map

groovy

So essentially I have something like this:

[a: ["c","d"], b: ["e","f"]]

The amount of items in each list is arbitrary. If there is only one item the list is no longer a list and it is a string.

I want to turn it into:

[ [a:"c", b:"e"], [a:"d",b:"f"] ]

I don't really care if the solution uses Groovy methods or not. Thanks for your help!

like image 366
James Kleeh Avatar asked Mar 22 '13 19:03

James Kleeh


People also ask

How do I convert a list to map in Groovy?

Using a SpreadMap we will convert a list of strings into a map. A SpreadMap is a helper that turns a list with an even number of elements into a Map. In the snippet below, we create a map keyed by NFL city while the value will be the team name.

How do I add a map to Groovy?

We can use the map literal syntax [k:v] for creating maps. Basically, it allows us to instantiate a map and define entries in one line. Notice that the keys aren't surrounded by quotes, and by default, Groovy creates an instance of java.

Are Groovy maps ordered?

In Groovy, maps created with the literal notation are ordered. We can expect our output to be in the same order as we defined in our original map.

What is Groovy Hashmap?

A hashmap maps a key to a value, but you are trying to map a key to two values. To do this, create a hashmap, where the key is your ID and the value is another hashmap, mapping the string "firstname" to "Jack" and the string "lastname" to "Sparrow" and so on for all <person> elements. Morten.


1 Answers

Here's another way to do it, that I think is less obscure while still being fairly concise:

def ml = [a: ["c","d"], b: ["e","f"]]

// Create an empty list that creates empty maps as needed
def lm = [].withDefault{ [:] }

ml.each{ k, values ->
    [values].flatten().eachWithIndex { value, index ->
        lm[index][k] = value
    }
}

assert lm == [[a:"c", b:"e"], [a:"d", b:"f"]]

If you don't want or cannot use withDefault (because you don't want the list to grow automatically), then this works too:

def ml = [a: ["c","d"], b: ["e","f"]]

def lm = []

ml.each{ k, values ->
    [values].flatten().eachWithIndex { value, index ->
        lm[index] = lm[index] ?: [:]
        lm[index][k] = value
    }
}

assert lm == [[a:"c", b:"e"], [a:"d", b:"f"]]

Edit: Added code to handle strings not contained within a list.

Note, the given trick ([values].flatten().eachWithIndex{...}) is not necessarily very efficient. If speed is essential, then using this would be slightly faster at the expense of readability:

(values instanceof List ? values : [values]).eachWithIndex{...}
like image 117
OverZealous Avatar answered Oct 14 '22 16:10

OverZealous