Need guidance on the syntax of nested looping in groovy. How to use iterator to print values of (value of a.name, value of b.name) here?
List a
a.each {
print(it.name)
List b = something
b.each {
print(value of a.name, value of b.name)
}
}
List a
a.each { x ->
println(x.name)
List b = something
b.each { y ->
println(x.name + y.name)
}
}
Related
I have a groovy map which looks like below.
image_map = [:]
image_map = [obj_1: ['1','2'], obj_2: ['3','4']]
I want to iterate through all the values(for obj_1, iterate throuth the list values['1','2']) for each object and run a method from the object.
obj_1.method(1)
obj_1.method(2)
obj_2.method(3)
obj_2.method(4)
Depends why you want to do it, but you could grab the values and flatten them:
image_map.values().flatten().each {
println it
}
So with the added requirement in the comment, you could do:
image_map.collectMany { k, v -> v.collect { "${k}.method($it)" } }
.each { println it }
To print
obj_1.method(1)
obj_1.method(2)
obj_2.method(3)
obj_2.method(4)
Edit 2 with another requirement... Assuming the keys ARE the objects (and not strings):
def obj_1 = [method: { it -> "I am obj1 $it" }]
def obj_2 = [method: { it -> "I am obj2 $it" }]
image_map = [(obj_1): ['1','2'], (obj_2): ['3','4']]
image_map.collectMany { k, v -> v.collect { [object: k, param: it] } }
.each { println it.object.method(it.param) }
Prints:
I am obj1 1
I am obj1 2
I am obj2 3
I am obj2 4
I have this piece of code all over my gradle file:
def itemA = getVar('ITEM_A')
if (itemA) {
envmap['itemA'] = itemA
}
def itemB = getVar('ITEM_B')
if (itemB) {
envmap['itemB'] = itemB
}
Is there a much concise way of assigning to a variable only if new value is not null or empty?
You could write a helper closure like so:
def envHelper = { map, vkey, mkey ->
getVar(vkey)?.with { v ->
envmap[mkey] = v
}
}
then, you can replace
def itemA = getVar('ITEM_A')
if (itemA) {
envmap['itemA'] = itemA
}
with
envHelper(envmap, 'ITEM_A', 'itemA')
Use collectEntries and findAll to get a Map.
//An example of keys corresponding to your query
def keyNameFromVarName(String varName){
varName.toLowerCase().replace('_','').substring(0,varName.length()-2)+
varName.substring(varName.length()-1,varName.length())
}
def varNames = ['ITEM_C', 'ITEM_D', 'ITEM_E', 'ITEM_F', 'ITEM_G', 'ITEM_H']
Map map = varNames.collectEntries{ [ (keyNameFromVarName(it)) : getVar(it) ] }.findAll{ k,v-> v }
First use collectEntries on the list object. Remember to put the generation of the map key inside parentheses or you will get a compilation error.
varNames.collectEntries{ [ (keyNameFromVarName(it)) : getVar(it) ] }
Then use findAll to get the entries where the value is not null. Define k,v as parameters to the closure for easy access to the value.
.findAll{ k,v-> v }
As I am reading values from a file in my Groovy code, I want to assign these values to the equivalent properties in my object as i am iterating through the map values!
code:
new ConfigSlurper().parse(new File(configManager.config.myFile.filepath)
.toURI().toURL()).each { k,v ->
if (k == 'something') {
v.each {
myObject.$it =v.$it
// so here i want this dynamic assignment to occur
}
}
}
You code there would already work like this, if you would use the form:
myObject."$it.key" = it.value
Here is a slightly more protective version:
class MyObject {
Long x,y
}
def obj = new MyObject()
def cfg = new ConfigSlurper().parse('''\
a {
x = 42
y = 666
}
b {
x = 93
y = 23
}''')
cfg.b.findAll{ obj.hasProperty(it.key) }.each{
obj.setProperty(it.key,it.value)
}
assert obj.x==93 && obj.y==23
I am getting the following error -
groovy.lang.MissingMethodException: No signature of method: Script64$_run_closure5_closure7_closure8_closure9_closure10_closure11.doCall() is applicable for argument types: (java.lang.String) values: Possible solutions: doCall(java.lang.Object, java.lang.Object), isCase(java.lang.Object), isCase(java.lang.Object) error at line:
Code - EDIT
import groovy.xml.*
List tempList = []
List listgenerated = []
def count = 0
for (a in 0..totalCount-1)
{
//nameList and valueList lists will have all the contents added as below commented pseudo code
/*for (b in 0..50)
{
nameList.add(b,number) // number is some calculated value
valueList.add(b,number)
e.g. nameList=[name1, name2, name3,name4, name5]
valueList =[val1, val2, val3, , val5]
listgenerated should be = [[name1:val1, name2:val2], [name3:val3, name4: , name5:val5]]
} */
tempList = []
for (j in count..nameList.size())
{
count = j
def nameKey = nameList[j]
def value
if (nameKey != null)
{
value = valueList[j]
tempList << [(nameKey) : value]
}
}
count = count
listgenerated.putAt(a,tempList)
number = number +1
}
def process = { binding, element, name ->
if( element[ name ] instanceof Collection ) {
element[ name ].each { n ->
binding."$name"( n )
}
}
else if( element[ name ] ) {
binding."$name"( element[ name ] )
}
}
class Form {
List fields
}
def list = [[ name:'a', val:'1' ], [ name:'b', val :'2', name2:4, xyz:'abc', pqr:'']] //Edited list
f = new Form( fields: list ) //Works fine
f = new Form( fields: listgenerated ) //Gives the above error
String xml = XmlUtil.serialize( new StreamingMarkupBuilder().with { builder ->
builder.bind { binding ->
data {
f.fields.each { fields ->
item {
fields.each { name, value ->
process( binding, fields, name )
}
}
}
}
}
} )
If while creating the "listgenerated" single quotes are added around values it takes it as character and while printing both lists seem different.
I am unable to figure it out what exactly is going wrong. Any help is appreciated. Thanks.
Ref - Groovy: dynamically create XML for collection of objects with collections of properties
I believe, where you do:
//some loop to add multiple values to the list
listgenerated << name+":"+value
You need to do:
//some loop to add multiple values to the list
listgenerated << [ (name): value ]
And add a map to the list rather than a String. It's hard to say though as your code example doesn't run without alteration, and I don't know if it's the alterations that are solving the problem
Given:
class FruitBasket {
int apples = 0
int oranges = 0
}
I need to pick out apples from each FruitBasket. The work need to be done in processFruit:
def processFruit(list, picker) {
list.each {
println "processing " + picker(it)
}
}
def processAll() {
List fruitList = [
new FruitBasket("apples": 2, "oranges": 4),
new FruitBasket("apples": 3, "oranges": 5)
]
processFruit(fruitList, applePicker)
}
def applePicker(FruitBasket f) {
return f.getApples()
}
but it is complaining # runtime that
No such property: applePicker for class: FooTest
possibly a problem with the closures FruitBasket arg...
In that code, applePicker is a method, not a closure.
You can either use a method handle to pass the method as a parameter like so:
processFruit(fruitList, this.&applePicker)
Or change it to an actual closure:
def applePicker = { FruitBasket f -> return f.getApples() }
You are passing applePicker to processFruit, but it is a method. You can only pass closures this way. Redefine applePicker as a closure like so:
applePicker = { FruitBasket f ->
return f.getApples()
}
Or convert the method to a closure when processFruit is called:
processFruit(fruitList, this.&applePicker)