How do I convert varargs to a single list even if the parameter is already a list? - groovy

I want a function that returns varargs as a list, such that
ensure_list(1, 2, 3)
returns
[1,2,3]
But the caveat is that I want
ensure_list([1, 2, 3])
to return the same value.
I tried
def ensure_list(Object... args) {
if (args instanceof List<Object>) {
return args
} else {
return Arrays.asList(args)
}
}
but I get
[[1,2,3]]
The input is enclosed in a list by the time it becomes args. Is there a way around this, or some other pattern that accomplishes what I want?

Consider flatten() which would facilitate a mixture of lists and args (if that is indeed desired):
def ensure_list(Object... args) {
args.flatten()
}
assert [1,2,3] == ensure_list(1, 2, 3)
assert [1,2,3] == ensure_list([1, 2, 3])
assert [1,2,3] == ensure_list([1, 2] , 3)

args is always an array, your test for if args is a List will always be false:
def foo(Object ... args) {
args.class.array // returns true
}
Instead check that the first element of args is a List:
def ensure_list(Object ... args) {
if (args.length == 1 && args[0] instanceof List) {
return args[0]
}
Arrays.asList(args)
}
groovy:000> ensure_list(1,2,3)
===> [1, 2, 3]
groovy:000> ensure_list([1,2,3])
===> [1, 2, 3]

Related

what is the difference between findResults and collect in groovy?

Here is the code using collect
​def lst = [1,2,3,4];
def newlst = [];
newlst = lst.collect {element -> return element * element}
println(newlst);
Here is the code using findResults
def lst2 = [1,2,3,4];
def newlst2 = [];
newlst2 = lst2.findResults {element -> return element * element}
println(newlst2);
​Both seem to return [1, 4, 9, 16] so what is the difference? Thanks!
Basically the difference is how they deal with null values
collect when sees null will collect it, while findResults won't pick it.
In other words, the size of resulting collection is the same as the size of input when using collect.
Of course you could filter out the results but its an additional step
Here is a link to the example I've found in the internet
Example:
​def list = [1, 2, 3, 4]
println list.coll​​​​​​​​​​​​​​ect { it % 2 ? it : null}
// [1, null, 3, null]
println list.findResults { it % 2 ? it : null}​
// [1,3]
When we need to check if returned list is empty then findResults seem more useful. Thanks to Mark for the answer.
def list = [1, 2, 3, 4]
def l1 = list.collect { it % 100 == 0 ? it : null}
def l2 = list.findResults { it % 100 == 0 ? it : null}
if(l1){
println("not null/empty " + l1)
}
if(l2){
println("not null/empty " + l2)
}
​

How to enforce maps of the same order using spock framework

The following test passes while I actually would like to see it fail. The order is important for my use case. However I thought groovy is always using linked lists so ordering should be testable.
def "test foo"() {
given:
def a = [a: 1, c: 3, b: 2]
when:
def b = [a: 1, b: 2, c: 3]
then:
a == b
}
If you want to test order of keys in those two LinkedHashMap instances you can do the following:
def "test foo"() {
given:
def a = [a: 1, c: 3, b: 2]
when:
def b = [a: 1, b: 2, c: 3]
then: "make sure maps are equal"
a == b
and: "make sure entries are defined in the same order"
a.collect { it.key } == b.collect { it.key }
}
LinkedHashMap does not override equals method (it uses the one defined in AbstractMap class, the same one used by e.g. HashMap) and it only defines order of the iteration (order in which entries are added to the map).
Both assertions can be simplified to a single:
def "test foo"() {
given:
def a = [a: 1, c: 3, b: 2]
when:
def b = [a: 1, b: 2, c: 3]
then: "compare ordered list of map entries"
a.collect { it } == b.collect { it }
}
You could use toMapString() in your comparison
a.toMapString() == b.toMapString()
toMapString converts the map into a String which means the order will impact the comparison
'[a:1, c:3, b:2]' == '[a:1, b:2, c:3]'
will return false.

How do I implement a comparator for a map in Groovy?

I have a map in Groovy:
['keyOfInterest' : 1, 'otherKey': 2]
There is a list containing a number of these maps. I want to know if a map exists in the list with keyOfInterest of a certain value.
If the data types were simple objects, I could use indexOf(), but I don't know how to do this with a more complicated type. E.g. (taken from the docs)
assert ['a', 'b', 'c', 'd', 'c'].indexOf('z') == -1 // 'z' is not in the list
I'd like to do something like:
def mapA = ['keyOfInterest' : 1, 'otherKey': 2]
def mapB = ['keyOfInterest' : 3, 'otherKey': 2]
def searchMap = ['keyOfInterest' : 1, 'otherKey': 5]
def list = [mapA, mapB]
assert list.indexOf(searchMap) == 0 // keyOfInterest == 1 for both mapA and searchMap
Is there a way to do this with more complicated objects, such as a map, easily?
While #dmahapatro is correct, and you can use find() to find the map in the list of maps that has the matching index... that's not what you asked for. So I'll show how you can get either the index of that entry in the list, or just whether a map with matching keyOfInterest exists.
def mapA = ['keyOfInterest' : 1, 'otherKey': 2]
def mapB = ['keyOfInterest' : 3, 'otherKey': 2]
def searchMap = ['keyOfInterest':1, 'otherKey': 55 ]
def list = [mapA, mapB]
// findIndexOf() returns the first index of the map that matches in the list, or -1 if none match
assert list.findIndexOf { it.keyOfInterest == searchMap.keyOfInterest } == 0
assert list.findIndexOf { it.keyOfInterest == 33 } == -1
// any() returns a boolean OR of all the closure results for each entry in the list.
assert list.any { it.keyOfInterest == searchMap.keyOfInterest } == true
assert list.any { it.keyOfInterest == 33 } == false
Note that there is no performance penalty for using one over the other as they all stop as soon as one match is found. find() gives you the most information, but if you're actually looking for the index or a boolean result, these others can also be used.
Simplest implementation would be to use find(). It returns null when criteria is not met in the supplied closure.
def mapA = ['keyOfInterest' : 1, 'otherKey': 2]
def mapB = ['keyOfInterest' : 3, 'otherKey': 2]
def list = [mapA, mapB]
assert list.find { it.keyOfInterest == 1 } == ['keyOfInterest':1, 'otherKey':2]
assert !list.find { it.keyOfInterest == 7 }

Groovy Element comparison

Is this madness, or is this Sparta?
groovy:000> b = [1,2,3,4]
===> [1, 2, 3, 4]
groovy:000> b.count { !it.equals(4) }
===> 0
groovy:000> b.count { !it == 4 }
===> 0
groovy:000> b.count { it == 4 }
===> 0
groovy:000> b.count { it == 1 }
===> 0
groovy:000> b[0]
===> 1
groovy:000> b.each { println it }
1
2
3
4
===> [1, 2, 3, 4]
groovy:000> print b.class
class java.util.ArrayList===> null
groovy:000> b.each { println it.class }
class java.lang.Integer
class java.lang.Integer
class java.lang.Integer
class java.lang.Integer
===> [1, 2, 3, 4]
groovy:000> 4.equals(b[3])
===> true
groovy:000>
I'm running into a case of "surprised expectations" here. Groovy tells me that I have an ArrayList of Integer, and I expect that I should be able to do cute little searches like the above 3 queries all tersely and sweetly. But no.
What is the idiomatic Groovy way of doing the above (count the number of elements where x != some element)
Why doesn't this work?
be aware that the method signature
public Number count(Closure closure)
is supported since Groovy 1.8.0 (current production is 1.7.10) - see http://groovy.codehaus.org/groovy-jdk/java/util/Collection.html#count(groovy.lang.Closure)
Before Groovy 1.8, the code above calls method 'count(Object value)', which counts the number of occurrences of the given value inside the collection. providing a closure instance as actual parameter 'value' leads to the results described above.
What is the idiomatic Groovy way of doing the above (count the number of elements where x != some element)
Here's one way:
def list = [3, 5, 3]
def countElementsNotEqualTo3 = list.findAll{ it != 3 }.size()
assert countElementsNotEqualTo3 == 1

How do I loop through a list and remove an item in groovy?

I'm trying to figure out how to remove an item from a list in groovy from within a loop.
static main(args) {
def list1 = [1, 2, 3, 4]
for(num in list1){
if(num == 2)
list1.remove(num)
}
println(list1)
}
list = [1, 2, 3, 4]
newList = list.findAll { it != 2 }
Should give you all but the 2
Of course you may have a reason for requiring the loop?
If you want to remove the item with index 2, you can do
list = [1,2,3,4]
list.remove(2)
assert list == [1,2,4]
// or with a loop
list = [1,2,3,4]
i = list.iterator()
2.times {
i.next()
}
i.remove()
assert list == [1,2,4]
If you want to remove the (first) item with value 2, you can do
list = [1,2,3,4]
list.remove(list.indexOf(2))
assert list == [1,3,4]
// or with a loop
list = [1,2,3,4]
i = list.iterator()
while (i.hasNext()) {
if (i.next() == 2) {
i.remove()
break
}
}
assert list == [1,3,4]
As you state in your comment that you do not specifically require a loop .... If you are happy to modify your original list you can use removeAll:
// Remove all negative numbers
list = [1, 2, -4, 8]
list.removeAll { it < 0 }
I think you can do:
list - 2;
or...
list.remove(2)
There's no loop required.
If you want to use a loop I guess you could look at using the iterator to actually remove the item.
import java.util.Iterator;
static main(args) { def list1 = [1, 2, 3, 4]
Iterator i = list1.iterator();
while (i.hasNext()) {
n = i.next();
if (n == 2) i.remove();
}
println(list1)
}​
but I don't see why you'd want to do it that way.

Resources