Groovy issue when checking maps in each closure - groovy

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. I.e. 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.

Related

Checking the equality of lists of Comparable objects in Groovy

I'm writing a test using the Spock framework and I found a strange bavior when testing equality of lists.
When I compare two lists like
sourceList == targetList
and those lists contains Comparable objects of the same type, those objects are tested for equality using its compareTo methods instead of equals.
Is there any simple way how to force Groovy to use equals when testing equality on such lists?
Here is a simple test specification where the test should fail, but it does not.
class Test extends Specification {
def "list test"() {
when:
def listA = [[index: 1, text: "1"] as Bean, [index: 2, text: "2"] as Bean]
def listB = [[index: 1, text: "1"] as Bean, [index: 2, text: "3"] as Bean]
then:
listA == listB
}
class Bean implements Comparable<Bean> {
int index
String text
#Override
public int compareTo(Bean o) {
return index.compareTo(o.index);
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + index;
result = prime * result + ((text == null) ? 0 : text.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (!(obj instanceof Bean)) {
return false;
}
Bean other = (Bean) obj;
if (index != other.index) {
return false;
}
if (text == null) {
if (other.text != null) {
return false;
}
} else if (!text.equals(other.text)) {
return false;
}
return true;
}
}
}
Asking for a simple method is subjective. The key to this answer is that, in Groovy, the is() method will check object equality.
Consider this new method on ArrayList. If appropriate, it will zip together the two lists and call is() on each pair of items.
ArrayList.metaClass.myCompare = { listB ->
def result = false
def listA = delegate
if (listB && listA.size() == listB.size()) {
def zipped = [listA, listB].transpose()
result = zipped.inject(true){ ok, pair ->
ok && pair[0].is(pair[1])
}
}
result
}
then:
def beanA = new Bean(index: 1, text: 'a')
def beanA1 = new Bean(index: 1, text: 'a')
def beanB = new Bean(index: 2, text: 'b')
assert [beanA, beanB].myCompare([beanA, beanB])
assert ! [beanA, beanB].myCompare([beanA1, beanB])
assert ! [beanA, beanB].myCompare([beanA])
assert ! [beanA, beanB].myCompare(null)
assert ! [beanA, beanB].myCompare([])
In groovy, "==" is replaced with equals if items are not comparable, or with compareTo if they implement Comparable. I do not know a simple way to force equals, if the collections have no duplicates, you can check the elements of the collection one by one:
def collectionsEqual (Collection<?> collection1, Collection<?> collection2) {
if (collection1.size() != collection2.size()) {
return false
}
for (elem1 in collection1) {
def founded = false;
for (elem2 in collection2) {
if (elem1?.equals (elem2)) {
founded = true
}
}
if (!founded) {
return false
}
}
true
}
but, in https://www.baeldung.com/java-compareto we have:
It is also strongly recommended, though not required, to keep the
compareTo implementation consistent with the equals method
implementation:
x.compareTo(y) == 0 should have the same boolean value as x.equals(y)
This will ensure that we can safely use objects in sorted sets and
sorted maps.

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 }

Inline Conditional Map Literal in Groovy

Working on some translation / mapping functionality using Maps/JsonBuilder in Groovy.
Is is possible (without creating extra code outside of the map literal creation) .. to conditionally include/exclude certain key/value pairs ? Some thing along the lines of the following ..
def someConditional = true
def mapResult =
[
"id":123,
"somethingElse":[],
if(someConditional){ return ["onlyIfConditionalTrue":true]}
]
Expected results:
If someConditional if false, only 2 key/value pairs will exist in mapResult.
If someConditional if true, all 3 key/value pairs will exist.
Note that I'm sure it could be done if I create methods / and split things up.. for to keep things concise I would want to keep things inside of the map creation.
You can help yourself with with:
[a:1, b:2].with{
if (false) {
c = 1
}
it
}
With a small helper:
Map newMap(m=[:], Closure c) {
m.with c
m
}
E.g.:
def m = newMap {
a = 1
b = 1
if (true) {
c = 1
}
if (false) {
d = 1
}
}
assert m.a == 1
assert m.b == 1
assert m.c == 1
assert !m.containsKey('d')
Or pass an initial map:
newMap(a:1, b:2) {
if (true) {
c = 1
}
if (false) {
d = 1
}
}
edit
Since Groovy 2.5, there is an alternative for with called tap. It
works like with but does not return the return value from the closure,
but the delegate. So this can be written as:
[a:1, b:2].tap{
if (false) {
c = 1
}
}
You could potentially map all false conditions to a common key (e.g. "/dev/null", "", etc) and then remove that key afterwards as part of a contract. Consider the following:
def condA = true
def condB = false
def condC = false
def mapResult =
[
"id":123,
"somethingElse":[],
(condA ? "condA" : "") : "hello",
(condB ? "condB" : "") : "abc",
(condB ? "condC" : "") : "ijk",
]
// mandatory, arguably reasonable
mapResult.remove("")
assert 3 == mapResult.keySet().size()
assert 123 == mapResult["id"]
assert [] == mapResult["somethingElse"]
assert "hello" == mapResult["condA"]
There is no such syntax, the best you can do is
def someConditional = true
def mapResult = [
"id":123,
"somethingElse":[]
]
if (someConditional) {
mapResult.onlyIfConditionalTrue = true
}
I agree with Donal, without code outside of map creation it is difficult.
At least you would have to implement your own ConditionalMap, it is a little work but perfectly doable.
Each element could have it's own condition like
map["a"] = "A"
map["b"] = "B"
map.put("c","C", true)
map.put("d","D", { myCondition })
etc...
Here an incomplete example (I did only put, get, keySet, values and size to illustrate, and not typed - but you probably don't need types here?), you will probably have to implement few others (isEmpty, containsKey etc...).
class ConditionalMap extends HashMap {
/** Default condition can be a closure */
def defaultCondition = true
/** Put an elemtn with default condition */
def put(key, value) {
super.put(key, new Tuple(defaultCondition, value))
}
/** Put an elemetn with specific condition */
def put(key, value, condition) {
super.put(key, new Tuple(condition, value))
}
/** Get visible element only */
def get(key) {
def tuple = super.get(key)
tuple[0] == true ? tuple[1] : null
}
/** Not part of Map , just to know the real size*/
def int realSize() {
super.keySet().size()
}
/** Includes only the "visible" elements keys */
def Set keySet() {
super.keySet().inject(new HashSet(),
{ result, key
->
def tuple = super.get(key)
if (tuple[0])
result.add(key)
result
})
}
/** Includes only the "visible" elements keys */
def Collection values() {
this.keySet().asCollection().collect({ k -> this[k] })
}
/** Includes only the "visible" elements keys */
def int size() {
this.keySet().size()
}
}
/** default condition that do not accept elements */
def map = new ConditionalMap(defaultCondition: false)
/** condition can be a closure too */
// def map = new ConditionalMap(defaultCondition : {-> true == false })
map["a"] = "A"
map["b"] = "B"
map.put("c","C", true)
map.put("d","D", false)
assert map.size() == 1
assert map.realSize() == 4
println map["a"]
println map["b"]
println map["c"]
println map["d"]
println "size: ${map.size()}"
println "realSize: ${map.realSize()}"
println "keySet: ${map.keySet()}"
println "values: ${map.values()}"
/** end of script */
You can use the spread operator to do this for for both maps and lists:
def t = true
def map = [
a:5,
*:(t ? [b:6] : [:])
]
println(map)
[a:5, b:6]
This works in v3, haven't tried in prior versions.

Is if(!x) the same as if(x!=null)

I know his is sort of a duplicate of Is if(pointerVar) the same as if(pointerVar!=NULL)?, but I have to ask anyway.
In Groovy, we have the following:
def x = someMethod()
if( !x ) {
// do good stuff
}
This is just a standard null check, ie (x != null), right?
No. if in groovy calls the underlying asBoolean() method. This is known as Groovy truth.
Empty lists, empty strings, empty maps, null, 0, are all falsy values:
if ([:]) {
assert false
}
if (null) {
assert false
}
if ("") {
assert false
}
if (0) {
assert false
}
assert null.asBoolean() == false
assert 1.asBoolean()
You can also write asBoolean in your own classes.

Recreating the if/else in groovy: giving multiple closures arguments to a function

While trying to reinvent the if/else syntax with closures in groovy, I couldn't manage to make it work. I think putting multiple closures outside the parenthesis is not permitted, but it could be something else.
If it isn't permitted, how would you reproduce the if/else syntax? This is a thought experiment, so don't tell me about the the inefficiency of this implementation.
My code:
void ifx(boolean condition, Closure action){
["${true.toString()}": action].get(condition.toString(), {})()
}
void ifx(boolean condition, Closure action, Closure elsex){
["${true.toString()}": action, "${false.toString()}": elsex].get(condition.toString())()
}
void elsex(Closure action){
action()
}
ifx(1==2){
println("1")
} ifx(1==3){
println("2")
} elsex{
println("3")
}
Error message:
java.lang.NullPointerException: Cannot invoke method ifx() on null
object
Something along these lines works:
updated with closures to avoid global state:
def ifx( outerCondition, outerBlock ) {
boolean matched = false
def realIfx
realIfx = { condition, block ->
if (condition) {
matched = true
block()
}
[ifx: realIfx, elsex: { elseBlock -> if(!matched) elseBlock() }]
}
realIfx outerCondition, outerBlock
}
And some testing:
def result
ifx(1 == 2) {
result = 1
} ifx(1 == 3) {
result = 2
} elsex {
result = 3
}
assert result == 3
result = null
ifx (1 == 2) {
result = 1
} ifx (2 == 2) {
result = 2
} elsex {
result = 3
}
assert result == 2
result = null
ifx (true) {
result = 1
} ifx (2 == 1) {
result = 2
} elsex {
result = 3
}
assert result == 1
ifx (1==2) {} ifx(1==3) {} elsex {} is a command chain expression translating to ifx(1==2,{}).ifx(1==3,{}).elsex({}). Since void translates to null, it should be clear that the second ifx call then fails with a NPE. To realize an if/else kind of thing I would maybe do the following
void ifx(boolean condition, Closure ifBlock, Closure elseBlock) {
....
}
ifx (1==2) {...}{...}
meaning not using an else keyword at all. IF you want to keep your idea, you have to return something on which you can call elsex and ifx.. Or if not ifx, then put a newline in after the first ifx

Resources