简体   繁体   中英

Groovy issue when checking maps in each closure

I have a utility method that needs to check if a Map<String,Integer> contains entries (keys) whose values are all zero (0):

def mapIsAllZeros(Map<String,Integer> toCheck) {
    println toCheck
    toCheck.each {
        if(it.value != 0) {
            return false
        } else {
            println "Value is : " + it.value
        }
    }

    println "Returning true..."
    true
}

Hence:

Map<String,Integer> m1 = new HashMap<String,Integer>()
m1.put("fizz", 0)
m1.put("buzz", 0)

Map<String,Integer> m2 = new HashMap<String,Integer>()
m2.put("fizz", 0)
m2.put("buzz", 1)

boolean m1Check = mapIsAllZeros(m1) // TRUE
boolean m2Check = mapIsAllZeros(m2) // FALSE

However when I run this method passing it m2 I get:

[fizz:0, buzz:1]
Value is : 0
Value is : 0
Returning true...

What's going on?

each can not return. use find instead. also this can be done in one line: [fizz:0, buzz:1].every{!it.value}

def mapIsAllZeros(Map<String,Integer> toCheck) {
    return toCheck.values().every{it==0}
}
assert !mapIsAllZeros([fizz: 0, buzz: 1])
assert !mapIsAllZeros([fizz: 1, buzz: 1])
assert mapIsAllZeros([fizz: 0, buzz: 0])
assert !mapIsAllZeros([fizz: null, buzz: null])

Edit: thanks to @dmahapatro: as the methods's name suggest a proper check against zero, let's not work with groovy-truth, so null :s wont result into something misleading

The problem here is that the return statement returns from the each closure, not from the mapIsAllZeros method. Ie the closure returns false and then each continues the iteration.

So you should use something other than each . For instance, using find :

boolean mapIsAllZeros(Map<String, Integer> toCheck) {
    !(toCheck.find { it.value != 0 })
}

Another alternative is to use a for loop:

boolean mapIsAllZeros(Map<String, Integer> toCheck) {
    for (entry in toCheck.entrySet()) {
        if (entry.value != 0) 
           return false
    }
    return true
}

The problem with returning from each closure was already clarified well, nevertheless You can also use the following piece of code (method name borrowed from @Steinar)

boolean mapIsAllZeros(Map<String, Integer> toCheck) {
   !toCheck.values().contains(0)
}

Simple and uses API that is well known.

A solution comparing unique values:

def mapIsAllZeros(map) {
  map*.value.unique() == [0]
}

assert !mapIsAllZeros([fizz: 0, buzz: 1])
assert !mapIsAllZeros([fizz: 1, buzz: 1])
assert mapIsAllZeros([fizz: 0, buzz: 0])

Because there are not enough answers here.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM