How to make a nested dictionary and dynamically append data
Solution 1
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)
Solution 2
Provided I've 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)
Solution 3
Look at the defaultdict
in the collections
module.
Here's a simple example that looks like what you're going for:
>>> 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 should just need this:
if mc.objExists(obj + ('.matteGroup')):
matteGroup = mc.getAttr(obj + ('.matteGroup'))
matteName = mc.getAttr(obj + ('.matteName'))
dizGroup[matteGroup][matteName].append(obj)
Solution 4
if speed is a concern, you could utilize try/except clauses to just try to populate your data first rather than checking if items exist and then adding it each 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 try/except, it would be best to put whatever exception maya throws if an attr doesn't exist on a node (don't have maya open right now, so I couldn't put that in...). This essentially checks for the attr and continues to the next obj if the attr isn't there. You can put them both in there instead of each having their own try/except, because it should error if either doesn't exist anyway.
the second try/except is checking if the matteGroup is in the top level of your dict. If it isn't, then you know the matteName and list of obj's isn't in your data structure either, so it adds them and continues to the next obj
the third try/except tries to append the obj to the matteName dict item's list. If you get a keyError here, it means that the matteName isn't in your matteGroup dict, so it then adds it and creates the list with the current obj as the first item in that list.
So, as far as speed is concerned, any time items exist in your data structure, the next obj you add to that data item will essentially just get added without having to test if all of the other data structure is in place before adding it, making your loop go faster the further into the loop you go (provided there are a lot of nodes sharing matteGroups and/or matteNames)
Related videos on Youtube
nookie
Updated on June 04, 2022Comments
-
nookie about 2 years
I have a loop giving me three variables
matteGroup matteName object
I would like to make a nested dicionary holding all the data like:
dictionary{matteGroup: {matteName: obj1, obj2, ob3} }
I am checking the objects one by one so I would like to create the
matteGroup
if it doesn't exist, create thematteName
if it doesn't exixst and then create or append the name of the object. I tryed a lot of solution like normal dictionaries, defaultdict and some custom classes I found on the net, but I haven't been able to do it properly. I have a nice nesting I am not able to append, or vice versa.This is the loop
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 the two dictionaries separately, but is not so useful! Any hint?
Thanks
-
silent_sight about 7 yearsyou could also combine the last two try/except clauses and just try to append the obj to the list first... it does get a little more difficult though, since you won't know which dict doesn't contain the key you're trying to access, so you have to account for that with nested try/except clauses if you really want to... aaaaaaand I just realized this question is from almost 5 and a half years ago, so I doubt anyone will even look at this answer, heh.