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
Related
I am starting with a collection as such:
def finalDocument = [[problem:problem1,fixed:true], [problem:problem1,fixed:false],[problem:problem1,fixed:false],[problem:problem2,fixed:true],[problem:problem2,fixed:false]]
What I want to do is create a map containing the problem and counts of how many are fixed, like this:
["problem1":[true:1,false:2],"problem2":[true:1,false:1]]
My end goal is to produce a percentage of fixed vs total for each problem
I'm trying to use groupBy to achieve this:
def output = finalDocument.groupby({it.problem},{it.fixed})
The resulting map is nested correctly but it gives me a list of the documents rather than a count of each, which I'm not sure how to achieve (I'm new to Groovy and scripting in general).
I'd put it like so:
def finalDocument = [[problem:'problem1',fixed:true], [problem:'problem1',fixed:false],[problem:'problem1',fixed:false],[problem:'problem2',fixed:true],[problem:'problem2',fixed:false]]
def res = finalDocument.groupBy{ [ it.problem, it.fixed ] }.inject( [:].withDefault{ [:] } ){ acc, grp, vals -> acc[ grp.first() ][ grp.last() ] = vals.size(); acc }
assert res.toString() == '[problem1:[true:1, false:2], problem2:[true:1, false:1]]'
I am doing some parse work with hl7apy parse, and i occurred with one problem.
I use hl7apy to parse hl7 message, which can be parse:
from hl7apy.parser import parse_message
message = "MSH|^~\&|HIS|HIS|MediII|MediII|20170902141711||ORM^O01^ORM_O01|15b 37e7132504a0b95ade4654b596dc5|P|2.4\r"
msg = parse_message(message, find_groups=False)
print(msg.msh.msh_3.msh_3_1.value)
output:
'HIS'
so, how can i get field value dynamically according to field config?
for example, the msh field config :
{
"field": "msh",
"field_index": [3,1]
}
so the value can be find with:
msg.msh.msh_3.msh_3_1.value
and if config change to:
{
"field": "pid",
"field_index": [2,4]
}
the get field line will be:
msg.pid.pid_2.pid_2_4.value
You could combine a few list comprehensions and use getattr recursively.
# recursively get the methods from a list of names
def get_method(method, names):
if names:
return get_method(getattr(method, names[0]), names[1:])
return method
field_config = {
'field': 'msh',
'field_index': [3, 1]
}
# just get the field
field = field_config['field']
# get a list of the indexes as string. ['3', '1']
indexes = [str(i) for i in field_config['field_index']]
# join the indexes with a '_' starting with nothing
# and put it in a list of names. ['msh', 'msh_3', 'msh_3_1']
names = ['_'.join([field] + indexes[:i]) for i in range(len(indexes) + 1)]
# get the method from the recursive function
method = get_method(msg, names)
print(method.value)
As a disclaimer, I had no way of testing it so it may not work exactly as you expect it. But this should be a good starting point.
def group_list(group, users):
members = [ print('{}:{}'.format(group,users) )]
return members
print(group_list("Marketing", ["Mike", "Karen", "Jake", "Tasha"]))
Output: Marketing:['Mike', 'Karen', 'Jake', 'Tasha']
[None]
Desired output : Marketing: Mike, Karen, Jake, Tasha
you can use str.join to make a single string out of the users list, without surrounding[].
and then your original format to add the Marketing: prefix, like this:
def group_list(group, users):
members = '{}: {}'.format(group,', '.join(users))
return members
print(group_list("Marketing", ["Mike", "Karen", "Jake", "Tasha"]))
Output:
Marketing: Mike, Karen, Jake, Tasha
The reason you got [None] is this is the return value from print, which you saved inside a list.
Just convert list to string using this function. And call list to string function inside your group list function where you're formatting to joining them.
def listToString(s):
# initialize an empty string
str1 = ", "
return (str1.join(s))
def group_list(group, users):
members = '{}: {}'.format(group,listToString(users))
return members
print(group_list("Marketing", ["Mike", "Karen", "Jake", "Tasha"]))
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.
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"])