How to use eval in nested dictionary in Python - nested

I have a dictionary similar to the below structure
sample_dict = {
'key1' : 'getVal1' ,
'key2' : 'getVal2' ,
'level1' :
{
'key3' : 'getVal3' ,
'level2' :
{
'key4' : 'getVal4'
}
}
}
I want to evaluate entire dictionary without accessing individual inner dict separately. (Eg : Without accessing 'level1' and 'level2' keys.)
The values are separate functions.. example is mentioned below.
def getVal1():
return "Some Calculation"
If it was a simple dict without nesting, it would be very simple to process, something like below.
final_dict = {k : eval(v) for k,v in sample_dict .items()}
But with nested dictionary, I am not able to construct.
If there is any generic way for this, it will be really helpful.

Related

sort keys across multiple dictionaries

I have a list that contains multiple small dictionaries, something like this:
_history = [{ "field" : "field01", "mode" : "write"},
{ "field" : "field02", "mode" : "write"},
{ "field" : "field03", "mode" : "write"},
{ "field" : "field01", "mode" : "clear"}]
What I'm interested in is the best way to process the list of dictionaries and determine if the same field value shows up more than once (in this case 'field01') and if it does, I'd like to verify whether the mode is the same. In the example above, I have a conflict on field01 and I'd like to raise an exception
You can do the following:
from itertools import groupby
from operator import itemgetter
def validate(hist)
key = itemgetter('field')
for k, g in groupby(sorted(hist, key=key), key=key):
s = set(d['mode'] for d in g)
if len(s) > 1:
raise ValueError(k)
>>> validate(_history)
Traceback ...
ValueError: field01

Getting value from nested map in groovy using a nested key

Suppose I have nested map like this
def someMap = [
a : [
b : [
c : "value",
d : "anothervalue"
]
]
]
I get the key at runtime as a string. Say it is "a.b.c"
How can I pull the value out of the map?
I know I can do myMap.a.b.c but for me, "a.b.c" is single string, I found out about at runtime?
Thanks
You could just go down the nodes likes this and try to get the respective child:
def key = "a.b.c"
def entry = someMap
key.split('\\.').each { entry = entry?.get(it) }
println entry?.value

loop find pattern in map - groovy

I want to loop through a map so if regex condition/pattern is met I will put the value into another map, else I will put in the map {trigger-all=true}.
This is what I got so far :
def patternsFunc = [
/(?s).*vee\/.*/ : "vee",
/(?s).*$HelmServicesPath\/vee\/.*/ : "vee",
/(?s).*rest\/.*/ : "rest",
/(?s).*$HelmServicesPath\/rest\/.*/ : "rest",
/(?s).*service\/.*/ : "service",
/(?s).*$HelmServicesPath\/service\/.*/ : "service",
]
patternsFunc.find { pattern, cname ->
if (file.find(pattern)) {
triggermap."trigger-${cname}" = true
assert triggermap."trigger-${cname}"
return true //found
} else {
return false
}
}
But there are 2 problems with this code:
the loop here going through every item on the patternsFunc map, so everything I put inside the "else" will happen whenever any of the conditions aren't met for every Item and not on the entire maps I need.
How do I put all values from the array to the map inside the "else"?
What I really need to achieve is in case no conditions are met, This will be the content of the map: {trigger-all=true}.
And when a condition(let's say "vee" and "rest") is met, This will be the content of the map: {trigger-rest=true,trigger-vee=true}.
First of all, find
finds the first result, but you want to find all, so use findAll.
Next don't mix side-effects into find or alike. Do the "finding"
first, then deal with the results. In this case, you want to build a
map from all the results. Use collectEntries for that.
And finally
you want a fallback, if nothing is found. So you can use the elvis
operator ?: to provide an alternative, if the resulting map is empty.
E.g.
def patterns = [
(/(?s).*service\/.*/): "service",
]
def file = '/service/'
def triggerMap = patterns.findAll{ // find relevant map entries
file.find(it.key)
}.collectEntries{ // build your map
["trigger-${it.value}", true]
} ?: ["trigger-all": true] // provide a fallback
Alternatively to what cfrick suggested, you can use inject method with an empty map as the initial value. That way you can iterate over all patterns, add entries if the pattern is found, and in the end, you can return ["trigger-all": true] map if no pattern was found.
Below you can find an example that tests 3 different file paths.
def patternsFunc = [
/(?s).*vee\/.*/ : "vee",
/(?s).*rest\/.*/ : "rest",
/(?s).*service\/.*/ : "service"
]
def files = [
"/tmp",
"/tmp/vee/1",
"/tmp/vee/rest/1"
]
files.each { file ->
def result = patternsFunc.inject([:]) { map, pattern, cname ->
file.find(pattern) ? map + ["trigger-$cname": true] : map
} ?: ["trigger-all": true]
println "Result for $file: $result"
}

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.

Nested dictionaries in Python: how to make them and how to use them?

I'm still trying to figure it out how nested dictionaries in python really works.
I know that when you're using [] it's a list, () it's a tuple and {} a dict.
But when you want to make a nested dictionaries like this structure (that's what a i want) :
{KeyA :
{ValueA :
[KeyB : ValueB],
[Keyc : ValueC],
[KeyD : ValueD]},
{ValueA for each ValueD]}}
For now I have a dict like:
{KeyA : {KeyB : [ValueB],
KeyC : [ValueC],
KeyD : [ValueD]}}
Here's my code:
json_file = importation()
dict_guy = {}
for key, value in json_file['clients'].items():
n_customerID = normalization(value['shortname'])
if n_customerID not in dict_guy:
dict_guy[n_customerID] = {
'clientsName':[],
'company':[],
'contacts':[], }
dict_guy[n_customerID]['clientsName'].append(n_customerID)
dict_guy[n_customerID]['company'].append(normalization(value['name']))
dict_guy[n_customerID]['contacts'].extend([norma_email(item) for item in v\
alue['contacts']])
Can someone please, give me more informations or really explain to me how a nested dict works?
So, I hope I get it right from our conversation in the comments :)
json_file = importation()
dict_guy = {}
for key, value in json_file['clients'].items():
n_customerID = normalization(value['shortname'])
if n_customerID not in dict_guy:
dict_guy[n_customerID] = {
'clientsName':[],
'company':[],
'contacts':{}, } # Assign empty dict, not list
dict_guy[n_customerID]['clientsName'].append(n_customerID)
dict_guy[n_customerID]['company'].append(normalization(value['name']))
for item in value['contacts']:
normalized_email = norma_email(item)
# Use the contacts dictionary like every other dictionary
dict_guy[n_customerID]['contacts'][normalized_email] = n_customerID
There is no problem to simply assign a dictionary to a key inside another dictionary. That's what I do in this code sample. You can create dictionaries nested as deep as you wish.
How that this helped you. If not, we'll work on it further :)
EDIT:
About list/dict comprehensions. You are almost right that:
I know that when you're using [] it's a list, () it's a tuple and {} a dict.
The {} brackets are a little tricky in Python 3. They can be used to create a dictionary as well as a set!
a = {} # a becomes an empty dictionary
a = set() # a becomes an empty set
a = {1,2,3} # a becomes a set with 3 values
a = {1: 1, 2: 4, 3: 9} # a becomes a dictionary with 3 keys
a = {x for x in range(10)} # a becomes a set with 10 elements
a = {x: x*x for x in range(10)} # a becomes a dictionary with 10 keys
Your line dict_guy[n_customerID] = { {'clientsName':[], 'company':[], 'contacts':[]}} tried to create a set with a single dictionary in it and because dictionaries are not hashable, you got the TypeError exception informing you that something is not hashable :) (sets can store only ements that are hashable)
Check out this page.
example = {'app_url': '', 'models': [{'perms': {'add': True, 'change': True,
'delete': True}, 'add_url': '/admin/cms/news/add/', 'admin_url': '/admin/cms/news/',
'name': ''}], 'has_module_perms': True, 'name': u'CMS'}

Resources