Update all object fields with a same value in a Groovy map - groovy

I have an Object in Groovy like:
class Person {
def name
def age
}
And a collection of persons stored in a map:
Person a = new Person(name: 'A', age:29)
Person b = new Person(name: 'B', age:15)
Map persons = ['1':a, '2':b]
I'm trying to update the age field for all persons, I know that I can do something like:
persons.each{ k,v -> v.age=0 }
But, I was wondering if is there another way to do it without iterating the entire map. As you can see, all persons should have the same value

You can use the spread operator:
persons.values()*.age = 0

Related

Move Dictionary Keys to lis for particular values

I trying to make this code work:
civil_freq= { '430.00': ['aaa'],
'430.02': ['aaa'],
'430.04': ['aaa'],
'430.06': ['bbb'],
'430.08': ['bbb'],
'430.10': ['bbb'],
'430.12': ['none'],
'430.14': ['none']}
person_freq=[]
person = 'bbb'
for key in civil_freq:
if civil_freq[key] == person:
person_freq.append(civil_freq.get(key))
print(person_freq)
it return empty list, but I need smth like
['430.06', '430.08', '430.10']
Issue: You're storing the persons names in a list (within your civil_freq dictionary) but comparing it with a string (variable person). This comparison won't work.
Try this:
person = ["bbb"]
for k, v in civil_freq.items():
if v == person:
person_freq.append(k)
print(person_freq)
or change the values within your dictionary from lists to strings!

How to loop through a map and display only one row if there is matching values

I have a map with differnt keys and multiple values.If there is any matching job among different keys,I have to display only one row and grouping code values.
def data = ['Test1':[[name:'John',dob:'02/20/1970',job:'Testing',code:51],[name:'X',dob:'03/21/1974',job:'QA',code:52]],
'Test2':[name:'Michael',dob:'04/01/1973',job:'Testing',code:52]]
for (Map.Entry<String, List<String>> entry : data.entrySet()) {
String key = entry.getKey();
List<String> values = entry.getValue();
values.eachWithIndex{itr,index->
println("key is:"+key);
println("itr values are:"+itr);
}
}
Expected Result : [job:Testing,code:[51,52]]
First flatten all the relevant maps, so whe just have a flat list of all of them, then basically the same as the others suggested: group by the job and just keep the codes (via the spread operator)
def data = ['Test1':[[name:'John',dob:'02/20/1970',job:'Testing',code:51],[name:'X',dob:'03/21/1974',job:'QA',code:52]], 'Test2':[name:'Michael',dob:'04/01/1973',job:'Testing',code:52]]
assert data.values().flatten().groupBy{it.job}.collectEntries{ [it.key, it.value*.code] } == [Testing: [51, 52], QA: [52]]
Note: the question will be changed according to the comments from the other answers.
Above code will give you the jobs and and their codes.
As of now, it's not clear, what the new expected output should be.
You can use the groovy's collection methods.
First you need to extract the lists, since you dont need the key of the top level element
def jobs = data.values()
Then you can use the groupBy method to group by the key "job"
def groupedJobs = jobs.groupBy { it.job }
The above code will produce the following result with your example
[Testing:[[name:John, dob:02/20/1970, job:Testing, code:51], [name:Michael, dob:04/01/1973, job:Testing, code:52]]]
Now you can get only the codes as values and do appropriate changes to make key as job by the following collect function
def result = groupedJobs.collect {key, value ->
[job: key, code: value.code]
}
The following code (which uses your sample data set):
def data = ['Test1':[name:'John', dob:'02/20/1970', job:'Testing', code:51],
'Test2':[name:'Michael', dob:'04/01/1973', job:'Testing', code:52]]
def matchFor = 'Testing'
def result = [job: matchFor, code: data.findResults { _, m ->
m.job == matchFor ? m.code : null
}]
println result
results in:
~> groovy solution.groovy
[job:Testing, code:[51, 52]]
~>
when run. It uses the groovy Map.findResults method to collect the codes from the matching jobs.

Adding Property to Double Class

I am running a clustering algorithm that clusters a collection of collections of Doubles. However once the clustering is done, I would like to figure out to which parent class each Double belongs to.
class PatientMRNA {
Patient patient
MRNA mrna
Double value
}
I am querying the database with hql and putting the selected values from the PatientMRNA table into a Collection like so:
[[x11,x12...x1m],[x21,x22...x2m]...[xn1, xn2, xnm]]
This collection gets clustered by a very nice algorithm found here: https://coviello.wordpress.com/2013/03/30/learning-functional-programming-a-k-means-implementation-in-groovy/
Once the clustering is done, our result is as follows:
[[centroid]: [[x?1, x?2...x?m],[x?1,x?2...x?m]...[x?1,x?2...x?m]] [centroid2]: [[],[]...[]]
Where each x array (belonging to a patient) value is randomized depending on the cluster it is assigned to.
My question is: Is there any way to extend the Double class in groovy so that it also has a PatientId property? Or should I really be looking at this problem in some other way?
kocko is wrong, as long as ALL of your code is in Groovy, you can use the instance metaClass as shown here:
// a list of patients
def patients = [ 'a', 'b', 'c', 'd', 'e' ]
// A list of doubles
def doubles = [ 5.0, 6.0, 2.0, 1.0, 9.0 ]
// for each double, set it's patient property to the parent at the same index
def decorated = [doubles, patients].transpose().collect { dbl, patient ->
dbl.metaClass.patient = patient
dbl
}
// sort it for fun, to prove it works
def sortedDecorated = decorated.sort(false)
// and print each out
sortedDecorated.each {
println "$it ${it.patient}"
}
That prints:
1.0 d
2.0 c
5.0 a
6.0 b
9.0 e
Of course, if you pass the list of doubles off to some Java code, then kocko is right as Java has no knowledge of the metaClass, so will just return you a list of plain undecorated Doubles

pulling a list based on the key

I have a record as
["name1":["value1":10, "value2":name1, "value3":150, "value4":20],
"name2":["value1":10, "value2":name2, "value3":150, "value4":20]]
I have a list where the values are name1, name2, etc.
I want to pull the list depending on the name1 as
["name1":["value1":10, "value2":name1, "value3":150, "value4":20]]
.subMap(["name1"]) did work for me, but I have a list and by looping the list I need to pull the values
Ex : namesList.each{record ->
newMap = firstmap.subMap(record)
}
Use subMap(Collection keys):
def map = ["name1":["value1":10, "value2":"name1", "value3":150, "value4":20],
"name2":["value1":10, "value2":"name2", "value3":150, "value4":20]]
//Answer here, return Map still:
println map.subMap("name1")
//Or
println map.subMap(["name1", "name2"])

getting distinct users from the resultset and string concat on other fields

I have a Sql ResultSet from a query. It has following fields: username, department, ..responsibility.
There are repeated username with different values for deptmt and responsblty. I want to get a map/list of unique usernames with a list of departments and responsibilities for each user in the resultset
So if
resultset = (Sam, dept1,.. resp1),
(Tom, dept1,..resp3),
(Sam,dept2,..resp2),
(Tom,dept3,..resp3)...etc
the output should be
finalList = [["Sam", "dept1,dept2", "resp1,resp2"],["Tom", "dept1,dept3", "resp3"]]
Things to note: 1) There may be n columns which are variable (column list read from a property file) so the code to be adaptable. _ not reqired for now, its a fixed list right now
2)All values enclosed in double quotes and seperated by comma.
3) For tom responsibility contains only resp3 since its repeated...i.e unique values in the list.
How do I convert the resultset?
Thanks
A shorter alternative to Bill's solution would be:
def data = [ ['Sam', 'dept1','resp1'],
['Tom', 'dept1','resp3'],
['Sam', 'dept2','resp2'],
['Tom', 'dept2','resp4'] ]
def output = data.groupBy { it[0] }.collect { name, vals ->
$/"$name", "${vals*.getAt( 1 ).join(',')}", "${vals*.getAt( 2 ).join(',')}"/$
}
output.each {
println it
}
Which prints:
"Sam", "dept1,dept2", "resp1,resp2"
"Tom", "dept1,dept2", "resp3,resp4"
This should get you pretty close. Note that the final output doesn't have the quotes in it (Groovy doesn't print those for strings). Looking at the code, you can see that the "output" is a Collection of Lists, each with 3 items: the name, the comma-sep list of department strings, then the comma-sep list of responsibility strings.
BTW, you may want to use something other than comma in the inner-strings, if you want to create a comma-sep list as the final output.
def data = [ ['Sam', 'dept1','resp1'],
['Tom', 'dept1','resp3'],
['Sam', 'dept2','resp2'],
['Tom', 'dept2','resp4'] ]
def tmpmap = [:]
data.each { inputrow ->
def name = inputrow[0]
def curlist = tmpmap[name]
if ( curlist == null ) { // first time seeing this name
curlist = [name,inputrow[1],inputrow[2]]
tmpmap.put( name, curlist );
} else { // seen this name before
curlist[1] += ',' + inputrow[1]
curlist[2] += ',' + inputrow[2]
}
}
output = tmpmap.values()
println output

Resources