groovy Hashmap - get the value count from a map - groovy

my following code
def traineeDetails = session.traineeDetailsForAuto
on printing gives:
traineeDetails = [name:[Hus, Vin], email:[hus#gmail.com, vin#gmail.com], phone:[9908877654, 9987655432], jobTitle:[SE, ST]]
def count = traineeDetails.name.size() gives correct value =2
but when the map key contains one value
def traineeDetails = session.traineeDetailsForAuto
on printing gives:
traineeDetails = [name:Hus, email:hus#gmail.com, phone:9987766543, jobTitle:SE]
def count= traineeDetails.name.size() gives wrong answer 3 which is the total number of character in name
but here i need to get total count of value that the key name holds..
how to do it?

If you're going to mix types in a map, then you're going to need to check the type:
def count = traineeDetails.name.with { it instanceof Collection ? it.size() : 1 }
Using your examples, it works fine:
traineeDetails = [name:['Hus', 'Vin'], email:['hus#gmail.com', 'vin#gmail.com'], phone:['9908877654', '9987655432'], jobTitle:['SE', 'ST']]
count = traineeDetails.name.with { it instanceof Collection ? it.size() : 1 }
assert count == 2
traineeDetails = [name:'Hus', email:'hus#gmail.com', phone:'9987766543', jobTitle:'SE']
count = traineeDetails.name.with { it instanceof Collection ? it.size() : 1 }
assert count == 1
Can you provide actual non-working examples?

Related

Loop with no duplicate values

Description of the problem.
Choose a number between 0 and 4 (the randomly number will indicate how many values from the list will be displayed)
Get random values from list, so that they are unique and display as a result.
My code does not work, please let me know how to fix it. I will be grateful for your help.
import groovy.json.JsonOutput
import java.util.Random
Random random = new Random()
def num = ["0","1","2","3","4"]
def randomNum = random.nextInt(num.size())
def min = 0;
def max = num[randomNum];
def list = ["Toy", "Mouse", "Cup","Book","Tiger"]
while(max > min) {
def randomValue = random.nextInt(list.size())
def theValue = list[randomValue] + '"'+ "," +
max++;
}
The result that I would like to achieve is for example:
Toy","Cup (if 2 is randomly selected)
Toy","Tiger","Book" (if 3 is randomly selected)
the available number is from 0 to 4 as many as there are possible
elements to choose from 0 - Toy, 1 - Mouse 2- Cup 3- Book 4 - tiger.
First, a number, e.g. 2, is drawn and then 2 elements are selected
randomly from the list of values.
You could do something like this:
Random random = new Random()
def list = ["Toy", "Mouse", "Cup","Book","Tiger"]
// this allows zero to be selected... if that is a violation
// of the requirement, adjust this....
int numberOfElementsToSelect = random.nextInt(list.size())
def results = []
numberOfElementsToSelect.times {
results << list.remove(random.nextInt(list.size()))
}
println results
println results.join(',')
EDIT:
Works great, I have one more question what to do to exit the script
without showing any results in case the value is empty
If you want to exit the script without showing results, you could do something like this:
Random random = new Random()
def list = ["Toy", "Mouse", "Cup","Book","Tiger"]
// this allows zero to be selected... if that is a violation
// of the requirement, adjust this....
int numberOfElementsToSelect = random.nextInt(list.size())
def results = []
numberOfElementsToSelect.times {
results << list.remove(random.nextInt(list.size()))
}
if(results) {
// do what you want with the results, like...
println results.join(',')
} else {
// do something else, could be exit the script...
System.exit(-2)
}

How to sort a list in descending order according to a map which is already sorted in descending order

I have a JSON array (list of maps) similar to:
def listOfMap = [[TESTCASE:1, METHOD:'CLICK', RESULT:'PASS'],
[TESTCASE:2, METHOD:'CLICK', RESULT:'FAIL'],
[TESTCASE:3, METHOD:'CLICK', RESULT:'FAIL'],
[TESTCASE:4, METHOD:'TYPETEXT', RESULT:'FAIL']]
I am grouping by the METHOD names and collecting the FAILURE % of each method
def percentage (map){
(map.FAIL ?: 0) / ((map.PASS ?: 0) + (map.FAIL ?: 0)) * 100
}
def result = listOfMap.groupBy{it.METHOD}
.collectEntries{[(it.key) : percentage(it.value.countBy{it.RESULT})]}
Now my output will be [CLICK : 66.6, TYPETEXT : 100]
To sort the above result in descending order of percentage,
def sortedResult = result.sort { a, b -> b.value <=> a.value }
Now my output will be [TYPETEXT : 100, CLICK : 66.6]
How can i get the FAIL count and PASS count of the METHOD linked to the above sorted order?
My output should be two separate lists (sorted in descending order of failure %)
passList = [0, 1] Note : [TYPETEXT passed 0 times, CLICK passed 1 time]
failList = [1, 2] Note : [TYPETEXT failed 1 time, CLICK failed 2 times]
Basically i am looking for this data to create a CSV report something like the below from the listofMap given:
Given this (from the original post):
def listOfMap = [[TESTCASE:1, METHOD:'CLICK', RESULT:'PASS'],
[TESTCASE:2, METHOD:'CLICK', RESULT:'FAIL'],
[TESTCASE:3, METHOD:'CLICK', RESULT:'FAIL'],
[TESTCASE:4, METHOD:'TYPETEXT', RESULT:'FAIL']]
Consider using Expando so that percentage is a field, but also passCount and failCount:
def percentage(passCount, failCount) {
failCount / (passCount + failCount) * 100
}
def result = listOfMap.groupBy{it.METHOD}.collectEntries{
def rec = new Expando()
def count = it.value.countBy{ it.RESULT }
rec."passCount" = count.'PASS' ?: 0
rec."failCount" = count.'FAIL' ?: 0
rec."percentage" = percentage(rec."passCount",
rec."failCount")
[(it.key) : rec]
}
def sortedResult = result.sort { a, b ->
b.value."percentage" <=> a.value."percentage"
}
sortedResult.each { println it }
The output matches the basic schema desired for the CSV:
$ groovy Example.groovy
TYPETEXT={failCount=1, percentage=100, passCount=0}
CLICK={failCount=2, percentage=66.6666666700, passCount=1}
You can do a multi-grouping to make your life easier:
def listOfMap = [[TESTCASE: 1, METHOD: 'CLICK', RESULT: 'PASS'],
[TESTCASE: 2, METHOD: 'CLICK', RESULT: 'FAIL'],
[TESTCASE: 3, METHOD: 'CLICK', RESULT: 'FAIL'],
[TESTCASE: 4, METHOD: 'TYPETEXT', RESULT: 'FAIL']]
def result = listOfMap.groupBy({ it.METHOD }, { it.RESULT })
.collectEntries { method, r ->
def passCount = r.PASS?.size() ?: 0
def failCount = r.FAIL?.size() ?: 0
[method, [passCount: passCount, failCount: failCount, failPercentage: (failCount / (passCount + failCount) * 100.0)]]
}.sort { -it.value.failPercentage }
You can then do:
result.values().failCount
or
result.values().passCount
to get the numbers you require in the question.
It's best to never try and keep multiple separate lists in the same order, much easier to store all the data together, and extract it after sorting the whole thing

Groovy: Get index of all occurences of sublist from arraylist

I am new to groovy and trying to find the indexes of all sublists in a list.
I am trying to use something like Collections.indexOfSubList like in java but it gives exception saying it applies on Lists and not ArrayLists.
So I am trying to define my own function. I am finding all the indices of all the elements in the smaller list existing in the longer list and then subtracting the indices of the result array. If it comes to 1 then I am considering that index to a sublist.
I know that I have the logic a little twisted. Can somebody guide with a better and efficient way of doing this.
Below is my code:
List list1 = [1,2,3,4,5,6,1,2,3]
List list2 = [1,2]
index1 = list1.findIndexValues {
it == list2[0];
}
index2 = list1.findIndexValues {
it == list2[1];
}
println index1
println index2
result = []
for (int i = 0; i < index1.size(); i++) {
result.add(index2[i]-index1[i]);
}
println result
Edit: no longer uses Collections due to new issue re: Elastic Search.
The following code traverses along the source list, creating a sublist. It checks the sublist to see if it starts with the target list. See the asserts below (e.g. the indexes are 0-based):
def listStartsWithSubList = { source, target ->
def result = false
if (source.size() >= target.size()) {
result = true
target.eachWithIndex { item, index ->
result = result && (item == source[index])
}
}
result
}
def indexOfSubLists = { source, target ->
def results = []
source.eachWithIndex { item, index ->
def tmpList = source[index..source.size()-1]
if (listStartsWithSubList(tmpList, target)) {
results << index
}
}
results
}
assert [1] == indexOfSubLists([1,2,3], [2,3])
assert [2] == indexOfSubLists([1,2,3], [3])
assert [] == indexOfSubLists([1,2,3], [4])
assert [0,6] == indexOfSubLists([1,2,3,4,5,6,1,2,3], [1,2])

Groovy iterating list variables

I am working on a script to collect field names (dialogPartyASelection_* && dialogPartyBSelection_*) and then compare the two values to see check if they match. The full list(selections)of fields is being broken down into 'groups' before comparison. I can break out certain parts (IE, comparing the two field values via iteration) and test successfully, however when bringing everything together the script doesn't seem to compare correctly. I may be approaching this/setting myself up to do this wrong, (have started to toy with creating a map, with party A as the key with party B as value).
Snippet of code:
// Test Variables
PartyBSelection_Propertieshamster = 'Accepted'
PartyBSelection_Propertieszembra = 'Agreed'
PartyBSelection_Propertiesdogs = 'Agreed'
PartyBSelection_Propertiescats = 'Decision taken'
PartyASelection_Propertieshamster = 'Accepted'
PartyASelection_Propertieszembra = 'Agreed'
PartyASelection_Propertiesdogs = 'Agreed'
PartyASelection_Propertiescats = 'Decision taken'
// example of selections(there are lots of entries for A/B party) = ['dialogPartyBSelection_Communication','dialogPartyASelection_Housing','dialogPartyASelection_Income','PartyASelection_Properties']
def selectedGroup = { s -> selections.findAll { it.contains s}} // for pulling groups of questions from list
def isAgreed = { a, b -> (a in ['Agreed', 'Decision taken','Accepted'] && b in ['Agreed', 'Decision taken','Accepted']) } // for comparing values
for(questions in selectedGroup("Properties")){
{k -> percentCompleteProperties += isAgreed("PartyASelection_${k}", "PartyBSelection_${k}")? 1 : 0}
println questions
println percentCompleteProperties
}
Current output:
PartyBSelection_Propertiescats
0
PartyBSelection_Propertieshamster
0
PartyBSelection_Propertiesdogs
0
PartyBSelection_Propertieshamster
0
PartyASelection_Propertiescats
0
PartyASelection_Propertieshamster
0
PartyASelection_Propertiesdogs
0
PartyASelection_Propertieshamster
0
This is sample code.
but i had changed test data etc.
please check whether this logic is correct for your case.
// Test Variables
def testVariables = [
'PartyBSelection_PropertiesAssets':'Accepted',
'PartyBSelection_PropertiesDebts': 'Agreed',
'PartyBSelection_PropertiesMoney': 'Agreed',
'PartyBSelection_PropertiesSpecialGoods':'Decision taken',
'PartyASelection_PropertiesAssets':'Accepted',
'PartyASelection_PropertiesDebts':'Agreed',
'PartyASelection_PropertiesMoney':'Agreed',
'PartyASelection_PropertiesSpecialGoods':'Decision taken'
]
List<String> selections= [
'PropertiesAssets',
'PropertiesDebts',
'PropertiesMoney',
'PropertiesSpecialGoods',
'PropertiesAssets',
'PropertiesDebts',
'PropertiesMoney',
'PropertiesSpecialGoods'
]
def selectedGroup = { s -> selections.findAll { it.contains s}}
List<String> okLabels = ['Agreed', 'Decision taken','Accepted']
def isAgreed = {a, b ->
(testVariables[a] in okLabels && testVariables[b] in okLabels)
}
List<Map<String, Integer>> result = selectedGroup("Properties").collect {String question ->
[(question) : isAgreed("PartyASelection_${question}", "PartyBSelection_${question}")? 1 : 0 ]
}
assert result == [
['PropertiesAssets':1],
['PropertiesDebts':1],
['PropertiesMoney':1],
['PropertiesSpecialGoods':1],
['PropertiesAssets':1],
['PropertiesDebts':1],
['PropertiesMoney':1],
['PropertiesSpecialGoods':1]
]
Other way
def r = [:]
def questionsCount = selectedGroup("Properties").size()
selectedGroup("Properties").eachWithIndex {String question, Integer i ->
println "question:${question}(${i+1}/${questionsCount})"
r.put(question,isAgreed("PartyASelection_${question}", "PartyBSelection_${question}")? 1 : 0 )
}
// This version includes all records in to the one map.
// Also, a record that is duplicated (as key) is overwritten.
r == [PropertiesAssets:1, PropertiesDebts:1, PropertiesMoney:1, PropertiesSpecialGoods:1]
then output:
question:PropertiesAssets(1/8)
question:PropertiesDebts(2/8)
question:PropertiesMoney(3/8)
question:PropertiesSpecialGoods(4/8)
question:PropertiesAssets(5/8)
question:PropertiesDebts(6/8)
question:PropertiesMoney(7/8)
question:PropertiesSpecialGoods(8/8)

Update map using findAll and each in groovy

I would like to update values in map in Groovy filling certain criteria. Here is my code:
def m = [:]
m['a'] = 1
m['b'] = 2
m['d'] = 3
m.findAll { it.value > 1}.each {
it.value = 4
}
println m
But the result is following:
[a:1, b:2, d:3]
Is there any way to do it using both findAll and each? Or I must use
m.each {if (it.value>1) it.value=4}
The root cause is findAll returns a new Map instance.
So you could try:
newMap = m.findAll { it.value > 1}.each {
it.value = 4
}
println m //No change
println newMap //This is what you need!
output is
[a:1, b:2, d:3]
[b:4, d:4]
In each case, the values you are iterating with the each are map entries with a pointer to key and value. When you set it.value you are not replacing what is in the map. You are only updating the pointer in the map entry. To actually set the value, you will need to do the following:
m.findAll { it.value > 1 }.each { m[it.key] = 4 }

Resources