196

I have a very simple task I am trying to do in Groovy but cannot seem to get it to work. I am just trying to loop through a map object in groovy and print out the key and value but this code does not work.

// A simple map
def map = [
        iPhone : 'iWebOS',
        Android: '2.3.3',
        Nokia  : 'Symbian',
        Windows: 'WM8'
]

// Print the values
for (s in map) {
    println s + ": " + map[s]
}

I am trying to get the output to look like this:

iPhone: iWebOS
Android: 2.3.3
Nokia: Symbian
Windows: WM8

Could someone please elaborate on how to do this??

friederbluemle
  • 33,549
  • 14
  • 108
  • 109
Kevin
  • 2,852
  • 6
  • 21
  • 33
  • As you have seen in the answers, the problem is that iterating over a map gives you a collection of "Entries", you were assuming it would give you the keys and you would look up the values. If you wanted to do it that way, iterate over map.keySet() and the rest will work as you expected. – Bill K Jun 13 '17 at 15:51
  • It should work if you use `s.key` & `s.value` in your code inside for loop. – inblueswithu Nov 14 '17 at 20:25

4 Answers4

370

Quite simple with a closure:

def map = [
           'iPhone':'iWebOS',
           'Android':'2.3.3',
           'Nokia':'Symbian',
           'Windows':'WM8'
           ]

map.each{ k, v -> println "${k}:${v}" }
Jack
  • 131,802
  • 30
  • 241
  • 343
  • 2
    Out of curiosity, where is this documented in the Groovy language docs (**I don't think it is!**)? I guess I'm wondering, from a Groovy newbies' perspective, *How did you know this?* – smeeb Oct 24 '15 at 10:40
  • 11
    @smeeb: everything is well documented, take a look here: http://www.groovy-lang.org/groovy-dev-kit.html#_iterating_on_maps – Jack Oct 24 '15 at 15:26
  • appreciating that this is a historic post: a for loop and an each closure are not one and the same and there may be times where the latter is preferred over the former. – Jay Edwards Mar 28 '23 at 09:53
121

Alternatively you could use a for loop as shown in the Groovy Docs:

def map = ['a':1, 'b':2, 'c':3]
for ( e in map ) {
    print "key = ${e.key}, value = ${e.value}"
}

/*
Result:
key = a, value = 1
key = b, value = 2
key = c, value = 3
*/

One benefit of using a for loop as opposed to an each closure is easier debugging, as you cannot hit a break point inside an each closure (when using Netbeans).

doelleri
  • 19,232
  • 5
  • 61
  • 65
ubiquibacon
  • 10,451
  • 28
  • 109
  • 179
  • I use GGTS 3.2 and routinely set break points in closures (including "each" closures). The problem is using F6 to step through a closure, as it will go over the whole thing. Technically, you can hit F5 a bunch of times and eventually end up in there, but a break point is faster. – Philip May 20 '13 at 09:35
  • Updated answer. I am using Netbeans and its debugging of Groovy/Grails is sub-par. – ubiquibacon May 20 '13 at 13:56
  • 5
    Plus you can break out a for loop and not in `.each`. – Alexander Suraphel Feb 17 '15 at 14:48
  • 1
    @AlexanderSuraphel you are correct that you cannot use `break` to exit `each`, but you can use `return` – ubiquibacon Jul 21 '15 at 14:30
  • 8
    @ubiquibacon no you can't. `return` is analogous to `continue` not `break`. – Alexander Suraphel Jul 21 '15 at 15:59
  • The disadvantage of using for loop is that if you have an empty map you will have error like this: Ambiguous expression could be either a parameterless closure expression or an isolated open code block; solution: Add an explicit closure parameter list, e.g. {it -> ...}, or force it to be treated as an open block by giving it a label, e.g. L:{...} @ line 1, column 1. {} – tstempko Feb 02 '16 at 08:56
  • Another reason to use this way: currently you can't use .each in jenkins groovy sandbox `FAILURE: Jenkins exception: java.lang.UnsupportedOperationException: Calling public static java.util.Map org.codehaus.groovy.runtime.DefaultGroovyMethods.each(java.util.Map,groovy.lang.Closure) on a CPS-transformed closure is not yet supported (JENKINS-26481); encapsulate in a @NonCPS method, or use Java-style loops` – Avner Sep 28 '17 at 01:12
23

When using the for loop, the value of s is a Map.Entry element, meaning that you can get the key from s.key and the value from s.value

sbglasius
  • 3,104
  • 20
  • 28
18

Another option:

def map = ['a':1, 'b':2, 'c':3]
map.each{
  println it.key +" "+ it.value
}
Pablo Pazos
  • 3,080
  • 29
  • 42