How to make a nested dictionary and dynamically add data

I have a loop giving me three variables

matteGroup matteName object 

I would like to make a nested dicionary containing all the data like:

 dictionary{matteGroup: {matteName: obj1, obj2, ob3} } 

I check the objects one by one, so I would like to create a matteGroup if it does not exist, create a matteName if it is not exixst, and then create or add the name of the object. I tried many solutions, such as regular dictionaries, defaultdict, and some custom classes that I found on the net, but I could not do it correctly. I have a good nesting that I cannot add, or vice versa.

It's a cycle

  dizGroup = {} dizName = {} for obj in mc.ls(type='transform'): if mc.objExists(obj + ('.matteGroup')): matteGroup = mc.getAttr(obj + ('.matteGroup')) matteName = mc.getAttr(obj + ('.matteName')) if matteGroup not in dizGroup: dizGroup[matteGroup] = list() dizGroup[matteGroup].append(matteName) if matteName not in dizName: dizName[matteName] = list() dizName[matteName].append(obj) 

with this I get two dictionaries separately, but it is not so useful! Any hint?

thanks

+4
source share
4 answers

try something like this

 dizGroup = {} for obj in mc.ls(type='transform'): if mc.objExists(obj + ('.matteGroup')): matteGroup = mc.getAttr(obj + ('.matteGroup')) matteName = mc.getAttr(obj + ('.matteName')) if matteGroup not in dizGroup: dizGroup[matteGroup] = {} if matteName not in dizGroup[matteGroup]: dizGroup[matteGroup][matteName] = [] dizGroup[matteGroup][matteName].append(obj) 
+4
source

Provided that I understood your requirements correctly:

 In [25]: from collections import defaultdict In [26]: d = defaultdict(lambda: defaultdict(list)) In [30]: for group, name, obj in [('g1','n1','o1'),('g1','n2','o2'),('g1','n1','o3'),('g2','n1','o4')]: ....: d[group][name].append(obj) 
+6
source

See defaultdict in the collections module.

Here is a simple example that looks the way you are going:

 >>> from collections import defaultdict >>> dizGroup = defaultdict(lambda:defaultdict(list)) >>> dizGroup['group1']['name1'].append(1) >>> dizGroup['group1']['name1'].append(2) >>> dizGroup['group1']['name1'].append(3) >>> dizGroup['group1']['name2'].append(4) >>> dizGroup['group1']['name2'].append(5) >>> dizGroup['group2']['name1'].append(6) >>> dizGroup defaultdict(<function <lambda> at 0x7ffcb5ace9b0>, {'group1': defaultdict(<type 'list'>, {'name2': [4, 5], 'name1': [1, 2, 3]}), 'group2': defaultdict(<type 'list'>, {'name1': [6]})}) 

So you just need this:

 if mc.objExists(obj + ('.matteGroup')): matteGroup = mc.getAttr(obj + ('.matteGroup')) matteName = mc.getAttr(obj + ('.matteName')) dizGroup[matteGroup][matteName].append(obj) 
+2
source

If speed is a concern, you can use try / except clauses to just try to populate your data first, rather than checking if elements exist, then adding them every time through the loop

 diz = {} for obj in mc.ls(type='transform'): try: matteGroup = mc.getAttr('%s.matteGroup' %obj) matteName = mc.getAttr('%s.matteName' %obj) except Exception: continue try: diz[matteGroup] except KeyError: diz[matteGroup] = {matteName : [obj]} continue try: diz[matteGroup][matteName].append(obj) except KeyError: diz[matteGroup][matteName] = [obj] 

for the first attempt / with the exception, it would be better to throw any maya exception if attr does not exist on node (now Maya does not open for me, so I could not put this in ...). This essentially checks attr and continues to the next obj if attr does not exist. You can put them both there, and not each of them has its own try / except, because this should be a mistake if either does not exist.

the second try / except checks if the matte group is at the top level of your dict. If this is not the case, then you know the name matteName, and the obj list is also not in your data structure, so it adds them and continues until the next obj

third attempt / excludes an attempt to add obj to the matteName dict list of elements. If you get keyError here, it means that matteName is not in your matteGroup dict, so it adds it and creates a list with the current obj as the first element in this list.

So, as far as speed is concerned, there are any time elements in your data structure, the next object added to this data element is essentially just added without checking if all other data structure is in place before adding it, making your cycle move faster into the cycle which you are going to (provided that many nodes share matte groups and / or matte names)

0
source

Source: https://habr.com/ru/post/1390045/


All Articles