short for python dictionary - python

I tried a few searches but I didn't really know how to ask. I understand short form for loops but this portion within a dictionary is confusing me.
resistances = {k: v if random.random() > self.mutProb else
not v for k, v in self.resistances.items()}
Is it setting k as the key initially and then cycling through it later on? I'm having difficulty imagining what the 'long hand' would be.

You have a dictionary comprehension, and for each iteration of the for loop, two expressions are executed. One for the key, and one for the value.
So in the expression:
{k: v if random.random() > self.mutProb else not v
for k, v in self.resistances.items()}
both k and v if random.random() > self.mutProb else not v are expressions, and the first produces the key, the second the value of each key-value pair for the resulting dictionary.
If you were to use a for loop, the above would be implemented as:
resistances = {}
for k, v in self.resistances.items():
key = k
value = v if random.random() > self.mutProb else not v
resistances[key] = value
In your example, the key is simply set to the value of the variable k, but you can use more complex expressions too.
Dictionary comprehensions are a specialisation of Dictionary Displays; the other form produces a dictionary without looping, from a static list of key-value pairs, and is perhaps more familiar to you:
d = {key1: value1, key2: value2}
but the documentation states:
A dict comprehension, in contrast to list and set comprehensions, needs two expressions separated with a colon followed by the usual “for” and “if” clauses. When the comprehension is run, the resulting key and value elements are inserted in the new dictionary in the order they are produced.

Related

Adding additional logic to a lambda function to get the minimum value from a python dictionary

I have a dictionary with values mapping some object to an integer; e.g. {node: 1, node: 2}.
I want to get the key that corresponds to the minimum value in this dictionary, which I know I can do with:
min_key = min(my_dict, key=lambda k: my_dict[k])
However, I'd also like to add the constraint that the key is not contained within some other set. Here's the pseudo-code that I wished worked:
min_key = min(my_dict, key=lambda k: my_dict[k] where k not in my_set)
Is there a way to write this as a one-liner in python as part of a lambda, or do I now have to explicitly loop through the dictionary and add the logic within the loop like this?
min_key, min_value = None, float('inf')
for k,v in my_dict.items():
if v < min_value and k not in my_set:
min_key = k
return min_key
Replace my_dict with a dictionary comprehension that returns the filtered dictionary.
min_key = min({k:v for k, v in my_dict.items() if k not in my_set},
key = lambda k: my_dict[k])
Just take the minimum over the filtered keys instead of all keys:
min_key = min(my_dict.keys() - my_set, key=my_dict.get)
(Note I also replaced your key function, no need to write your own.)
It's similar to #Barmar's answer but you can also use set.difference between my_dict and my_set to filter the relevant dictionary:
out = min(set(my_dict).difference(my_set), key = lambda k: my_dict[k])

Returning unique elements from values in a dictionary

I have a dictionary like this :
d = {'v03':["elem_A","elem_B","elem_C"],'v02':["elem_A","elem_D","elem_C"],'v01':["elem_A","elem_E"]}
How would you return a new dictionary with the elements that are not contained in the key of the highest value ?
In this case :
d2 = {'v02':['elem_D'],'v01':["elem_E"]}
Thank you,
I prefer to do differences with the builtin data type designed for it: sets.
It is also preferable to write loops rather than elaborate comprehensions. One-liners are clever, but understandable code that you can return to and understand is even better.
d = {'v03':["elem_A","elem_B","elem_C"],'v02':["elem_A","elem_D","elem_C"],'v01':["elem_A","elem_E"]}
last = None
d2 = {}
for key in sorted(d.keys()):
if last:
if set(d[last]) - set(d[key]):
d2[last] = sorted(set(d[last]) - set(d[key]))
last = key
print d2
{'v01': ['elem_E'], 'v02': ['elem_D']}
from collections import defaultdict
myNewDict = defaultdict(list)
all_keys = d.keys()
all_keys.sort()
max_value = all_keys[-1]
for key in d:
if key != max_value:
for value in d[key]:
if value not in d[max_value]:
myNewDict[key].append(value)
You can get fancier with set operations by taking the set difference between the values in d[max_value] and each of the other keys but first I think you should get comfortable working with dictionaries and lists.
defaultdict(<type 'list'>, {'v01': ['elem_E'], 'v02': ['elem_D']})
one reason not to use sets is that the solution does not generalize enough because sets can only have hashable objects. If your values are lists of lists the members (sublists) are not hashable so you can't use a set operation
Depending on your python version, you may be able to get this done with only one line, using dict comprehension:
>>> d2 = {k:[v for v in values if not v in d.get(max(d.keys()))] for k, values in d.items()}
>>> d2
{'v01': ['elem_E'], 'v02': ['elem_D'], 'v03': []}
This puts together a copy of dict d with containing lists being stripped off all items stored at the max key. The resulting dict looks more or less like what you are going for.
If you don't want the empty list at key v03, wrap the result itself in another dict:
>>> {k:v for k,v in d2.items() if len(v) > 0}
{'v01': ['elem_E'], 'v02': ['elem_D']}
EDIT:
In case your original dict has a very large keyset [or said operation is required frequently], you might also want to substitute the expression d.get(max(d.keys())) by some previously assigned list variable for performance [but I ain't sure if it doesn't in fact get pre-computed anyway]. This speeds up the whole thing by almost 100%. The following runs 100,000 times in 1.5 secs on my machine, whereas the unsubstituted expression takes more than 3 seconds.
>>> bl = d.get(max(d.keys()))
>>> d2 = {k:v for k,v in {k:[v for v in values if not v in bl] for k, values in d.items()}.items() if len(v) > 0}

change key to lower case for dict or OrderedDict

Following works for a dictionary, but not OrderedDict. For od it seems to form an infinite loop. Can you tell me why?
If the function input is dict it has to return dict, if input is OrderedDict it has to return od.
def key_lower(d):
"""returns d for d or od for od with keys changed to lower case
"""
for k in d.iterkeys():
v = d.pop(k)
if (type(k) == str) and (not k.islower()):
k = k.lower()
d[k] = v
return d
It forms an infinite loop because of the way ordered dictionaries add new members (to the end)
Since you are using iterkeys, it is using a generator. When you assign d[k] = v you are adding the new key/value to the end of the dictionary. Because you are using a generator, that will continue to generate keys as you continue adding them.
You could fix this in a few ways. One would be to create a new ordered dict from the previous.
def key_lower(d):
newDict = OrderedDict()
for k, v in d.iteritems():
if (isinstance(k, (str, basestring))):
k = k.lower()
newDict[k] = v
return newDict
The other way would be to not use a generator and use keys instead of iterkeys
As sberry mentioned, the infinite loop is essentially as you are modifying and reading the dict at the same time.
Probably the simplest solution is to use OrderedDict.keys() instead of OrderedDict.iterkeys():
for k in d.keys():
v = d.pop(k)
if (type(k) == str) and (not k.islower()):
k = k.lower()
d[k] = v
as the keys are captured directly at the start, they won't get updated as items are changed in the dict.

Search Python dictionary where value is list

If I had a dictionary where the value was set to a list by default, how could I go about searching all of these lists in the dictionary for a certain term?
For Example:
textbooks = {"math":("red", "large"), "history":("brown", "old", "small")}
With more terms and cases where the same thing might occur again, how could I say find all of the keys in which their value is a list containing "red"? In my example above, the only one I'd want it to find would be "math".
[k for k, v in textbooks.iteritems() if 'red' in v]
It is Pythonic shorthand for
res = []
for key, val in textbooks.iteritems():
if 'red' in val:
res.append(key)
See list comprehension in Python documentation
[key for key, corresponding_list in textbook.items() if 'red' in corresponding_list]

Is there a more pythonic way to do this dictionary iteration?

I have a dictionary in the view layer, that I am passing to my templates. The dictionary values are (mostly) lists, although a few scalars also reside in the dictionary. The lists if present are initialized to None.
The None values are being printed as 'None' in the template, so I wrote this little function to clean out the Nones before passing the dictionary of lists to the template. Since I am new to Python, I am wondering if there could be a more pythonic way of doing this?
# Clean the table up and turn Nones into ''
for k, v in table.items():
#debug_str = 'key: %s, value: %s' % (k,v)
#logging.debug(debug_str)
try:
for i, val in enumerate(v):
if val == None: v[i] = ''
except TypeError:
continue;
Have you looked at defaultdict within collections? You'd have a dictionary formed via
defaultdict(list)
which initializes an empty list when a key is queried and that key does not exist.
filtered_dict = dict((k, v) for k, v in table.items() if v is not None)
or in Python 2.7+, use the dictionary comprehension syntax:
filtered_dict = {k: v for k, v in table.items() if v is not None}

Categories