I am trying to find a way of deleting duplicate shaders in Maya using Python Dictionaries.
Here is what I'm doing:
I want to put all maya shaders into a dictionary as keys and put the corresponding texture file as the value. Then I want the script to run through the dictionary and find any keys that share the same value and stuff them into an array or another dictionary.
This is basically what I have right now:
shaders_dict = {'a': somePath, 'b': somePath,
'c': differentPath, 'd': differentPath}
duplicate_shaders_dict = {}`
how can I now run through that dictionary to compile another dictionary that looks something like this:
duplicate_shaders_dict = {'b':somePath, 'd':differentPath }
And the tricky part being since there are duplicates I want the script to skip the original key
so it doesn't also get stuffed in to duplicate shaders dictionary.
Dictionaries in Python First, a given key can appear in a dictionary only once. Duplicate keys are not allowed.
The straight answer is NO. You can not have duplicate keys in a dictionary in Python. But we can have a similar effect as keeping duplicate keys in dictionary.
I would probably do something like this. First, make the inverse dictionary:
>>> from collections import defaultdict
>>>
>>> shaders_dict = {'a':'somePath', 'b':'somePath', 'c':'differentPath', 'd':'differentPath'}
>>>
>>> inverse_dict = defaultdict(list)
>>> for k,v in shaders_dict.iteritems():
... inverse_dict[v].append(k)
...
>>> inverse_dict
defaultdict(<type 'list'>, {'differentPath': ['c', 'd'], 'somePath': ['a', 'b']})
This basically inverts the dictionary by looping over every key, value pair and appending the key to a list associated with the value.
Then split this:
>>> first_shaders_dict = {}
>>> duplicate_shaders_dict = {}
>>> for v, ks in inverse_dict.iteritems():
... first, rest = ks[0], ks[1:]
... first_shaders_dict[first] = v
... for r in rest:
... duplicate_shaders_dict[r] = v
...
>>> first_shaders_dict
{'a': 'somePath', 'c': 'differentPath'}
>>> duplicate_shaders_dict
{'b': 'somePath', 'd': 'differentPath'}
Hmm. This assumes that the texture files are hashable and so can serve as dictionary keys. If they're not, then I'd have to work around that. Also, since as @freespace notes there's no ordering here, if you wanted a particular order we'd have to iterate over sorted keys or the like.
--
Update: I didn't like the above much. Shorter itertools-based version:
>>> import itertools
>>> shaders_dict = {'a':'somePath', 'b':'somePath', 'c':'differentPath', 'd':'differentPath'}
>>> keys = sorted(sorted(shaders_dict),key=shaders_dict.get)
>>> by_val = [(v, list(ks)) for v, ks in itertools.groupby(keys, shaders_dict.get)]
>>> first_dict = dict((ks[0],v) for v,ks in by_val)
>>> duplicate_dict = dict((k,v) for v,ks in by_val for k in ks[1:])
>>> first_dict
{'a': 'somePath', 'c': 'differentPath'}
>>> duplicate_dict
{'b': 'somePath', 'd': 'differentPath'}
One simple solution is to reverse the dictionary. Given:
>>> d = {'a': 'somePath', 'b': 'somePath',
... 'c': 'differentPath', 'd': 'differentPath'}
You can reverse it like this:
>>> r = dict((v,k) for k,v in d.iteritems())
Which gives you:
>>> r
{'differentPath': 'd', 'somePath': 'b'}
And if you reverse that, you have the original dictionary with duplicates removed:
>>> d = dict((v,k) for k,v in r.iteritems())
>>> d
{'b': 'somePath', 'd': 'differentPath'}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With