I am new to groovy and I\'ve been facing some issues understanding the each{}
and eachwithindex{}
statements in groovy.
Are each
a
EachWithIndex
can be used as follows:
package json
import groovy.json.*
import com.eviware.soapui.support.XmlHolder
def project = testRunner.testCase.testSuite.project
def testCase = testRunner.testCase;
def strArray = new String[200]
//Response for a step you want the json from
def response = context.expand('${Offers#Response#$[\'Data\']}').toString()
def json = new JsonSlurper().parseText(response)
//Value you want to compare with in your array
def offername = project.getPropertyValue("Offername")
log.info(offername)
Boolean flagpresent = false
Boolean flagnotpresent = false
strArray = json.Name
def id = 0;
//To find the offername in the array of offers displayed
strArray.eachWithIndex
{
name, index ->
if("${name}" != offername)
{
flagnotpresent= false;
}
else
{
id = "${index}";
flagpresent = true;
log.info("${index}.${name}")
log.info(id)
}
}
Normally, if you are using a functional programing language such as Groovy, you would want to avoid using each
and eachWithIndex
since they encourage you to modify state within the closure or do things that have side effects.
If possible, you may want to do your operations using other groovy collection methods such as .collect
or .inject
or findResult
etc.
However, to use these for your problem, i.e print the list elements with their index, you will need to use the withIndex
method on the original collection which will transform the collection to a collection of pairs of [element, index]
For example,
println(['a', 'b', 'c'].withIndex())
These are plain methods but they follow quite a specific pattern - they take a Closure
as their last argument. A Closure is a piece of functionality that you can pass around and call when applicable.
For example, method eachWithIndex might look like this (roughly):
void eachWithIndex(Closure operation) {
for (int i = 0; this.hasNext(); i++) {
operation(this.next(), i); // Here closure passed as parameter is being called
}
}
This approach allows one to build generic algorithms (like iteration over items) and change the concrete processing logic at runtime by passing different closures.
Regarding the parameters part, as you see in the example above we call the closure (operation
) with two parameters - the current element and current index. This means that the eachWithIndex method expects to receive not just any closure but one which would accept these two parameters. From a syntax prospective one defines the parameters during closure definition like this:
{ elem, index ->
// logic
}
So ->
is used to separate arguments part of closure definition from its logic. When a closure takes only one argument, its parameter definition can be omitted and then the parameter will be accessible within the closure's scope with the name it
(implicit name for the first argument). For example:
[1,2,3].each {
println it
}
It could be rewritten like this:
[1,2,3].each({ elem ->
println elem
})
As you see the Groovy language adds some syntax sugar to make such constructions look prettier.
each
and eachWithIndex
are, amongst many others, taking so called Closure
as an argument. The closure is just a piece of Groovy code wrapped in {}
braces. In the code with array:
def numbers = [ 5, 7, 9, 12 ]
numbers.eachWithIndex{ num, idx -> println "$idx: $num" }
there is only one argument (closure, or more precisely: function), please note that in Groovy ()
braces are sometime optional. num
and idx
are just an optional aliases for closure (function) arguments, when we need just one argument, this is equivalent (it
is implicit name of the first closure argument, very convenient):
def numbers = [ 5, 7, 9, 12 ]
numbers.each {println "$it" }
References: