I want to make a IF statement inside a for loop, that I want it to be triggered if the variable is equal to any value in the list.
Sample data:
list = [variable1, variable2, variable3]
Right now I have this sample code:
for k, v in result_dict.items():
if k == 'varible1' or k == 'variable2' or k == 'variable2':
But the problem is the list will grow larger and I don't to have to create multiple OR statements for every variable.
how can I do it?
This is what the in operator is for. Do:
list = [variable1, variable2, variable3]
for k, v in result_dict.items():
if k in list:
Another way to do it is with sets:
>>> l = ['a', 'b', 'c']
>>> d = {'a': 1, 'b': 2, 'c': 'three', 'd': 4, 'e': 5, 'f': 6}
>>> keys = set(l).intersection(d.keys())
>>> keys
set(['a', 'c', 'b'])
Then you can iterate over those keys:
for k in set(l).intersection(d.keys()):
do_something(d[k])
This should be more efficient than repetitively calling in on the list. Call set() on the shortest of the list or dictionary.
You may need another FOR loop.
for k, v in result_dict.items():
for i in list:
if i==k:
Related
For example, in dict1 the keys 1, 2, 3 all have the same value 'a', but the keys 3 and 5 have different values, 'b' and 'd'. What I want is:
If N keys have the same value and N >=3, then I want to remove all other elements from the dict and only keep those N key values, which means 'b' & 'd' have to be removed from the dict.
The following code works, but it seems very verbose. Is there a better way to do this?
from collections import defaultdict
dict1 = {1:'a', 2:'a', '3':'b', '4': 'a', '5':'d'}
l1 = [1, 2, 3, 4, 5]
dict2 = defaultdict(list)
for k, v in dict1.items():
dict2[v].append(k)
to_be_removed = []
is_to_be_removed = False
for k, values in dict2.items():
majority = len(values)
if majority>=3:
is_to_be_removed = True
else:
to_be_removed.extend(values)
if is_to_be_removed:
for d in to_be_removed:
del dict1[d]
print(f'New dict: {dict1}')
You can use collections.Counter to get the frequency of every value, then use a dictionary comprehension to retain only the keys that have the desired corresponding value:
from collections import Counter
dict1 = {1:'a', 2:'a', '3':'b', '4': 'a', '5':'d'}
ctr = Counter(dict1.values())
result = {key: value for key, value in dict1.items() if ctr[value] >= 3}
print(result)
This outputs:
{1: 'a', 2: 'a', '4': 'a'}
This question already has answers here:
is it possible to reverse a dictionary in python using dictionary comprehension
(5 answers)
Closed 2 years ago.
While I've been improving my Python skills I have one question.
My code is below:
# def invertDictionary(dict):
# new_dict = {}
# for key, value in dict.items():
# if value in new_dict:
# new_dict[value].append(key)
# else:
# new_dict[value]=[key]
# return new_dict
def invertDictionary(dict):
new_dict = {value:([key] if value else [key]) for key, value in dict.items()}
return new_dict;
invertDictionary({'a':3, 'b':3, 'c':3})
I am trying to get output like {3:['a','b','c']}. I have achieved that using a normal for-loop; I just want to know how to get these results using a Dictionary Comprehension. I tried but in append it's getting an error. Please let me know how to achieve this.
Thanks in Advance!
You missed that you also need a list comprehension to build the list.
Iterate over the values in the dict, and build the needed list of keys for each one.
Note that this is a quadratic process, whereas the canonical (and more readable) for loop is linear.
d = {'a':3, 'b':3, 'c':3, 'e':4, 'f':4, 'g':0}
inv_dict = {v: [key for key, val in d.items() if val == v]
for v in set(d.values())}
result:
{0: ['g'],
3: ['a', 'b', 'c'],
4: ['e', 'f']
}
Will this do?
while your original version with a regular for loop is the best solution for this, here is a variation on #Prune answer that doesn't goes over the dict multiple times
>>> import itertools
>>> d = {'a':3, 'b':3, 'c':3, 'e':4, 'f':4, 'g':0}
>>> {group_key:[k for k,_ in dict_items]
for group_key,dict_items in itertools.groupby(
sorted(d.items(),key=lambda x:x[-1]),
key=lambda x:x[-1]
)
}
{0: ['g'], 3: ['a', 'b', 'c'], 4: ['e', 'f']}
>>>
first we sorted the items of the dict by value with a key function to sorted using a lambda function to extract the value part of the item tuple, then we use the groupby to group those with the same value together with the same key function and finally with a list comprehension extract just the key
--
as noted by Kelly, we can use the get method from the dict to get the value to make it shorter and use the fact that iteration over a dict give you its keys
>>> {k: list(g) for k, g in itertools.groupby(sorted(d, key=d.get), d.get)}
{0: ['g'], 3: ['a', 'b', 'c'], 4: ['e', 'f']}
>>>
You could use a defalutdict and the append method.
from collections import defaultdict
dict1 = {'a': 3, 'b': 3, 'c': 3}
dict2 = defaultdict(list)
{dict2[v].append(k) for k, v in dict1.items()}
dict2
>>> defaultdict(list, {3: ['a', 'b', 'c']})
I want to create two dictionaries in python by dictionary comprehension at the same time. The two dictionaries share the same key set, but have different values for each key. Therefore, I use a function to return a tuple of two values, and hoping a dictionary comprehension can create these two dictionaries at the same time.
Say, I have a function
def my_func(foo):
blablabla...
return a, b
And I will create two dictionaries by
dict_of_a, dict_of_b = ({key:my_func(key)[0]}, {key:my_func(key)[1]} for key in list_of_keys)
Is there any better code to improve it? In my opinion, my_func(key) will be called twice in each iteration, slowing down the code. What is the correct way to do it?
With ordered slicing:
def myfunc(k):
return k + '0', k + '1'
list_of_keys = ['a', 'b', 'c']
groups = [(k,v) for k in list_of_keys for v in myfunc(k)]
dict_of_a, dict_of_b = dict(groups[::2]), dict(groups[1::2])
print(dict_of_a) # {'a': 'a0', 'b': 'b0', 'c': 'c0'}
print(dict_of_b) # {'a': 'a1', 'b': 'b1', 'c': 'c1'}
for key in list_of_keys:
dict_of_a[key],dict_of_b[key] = my_func(key)
The regular loop is probably the best way to go. If you want to play with functools, you can write:
>>> def func(foo): return foo[0], foo[1:]
...
>>> L = ['a', 'ab', 'abc']
>>> functools.reduce(lambda acc, x: tuple({**d, x: v} for d, v in zip(acc, func(x))), L, ({}, {}))
({'a': 'a', 'ab': 'a', 'abc': 'a'}, {'a': '', 'ab': 'b', 'abc': 'bc'})
The function reduce is a fold: it takes the current accumulator (here the dicts being built) and the next value from L:
d, v in zip(acc, func(x)) extracts the dicts one at a time and the matching element of the return value of func;
{**d, x: v} update the dict with the current value.
I don't recommend this kind of code since it's hard to maintain.
my_func(key) will be called twice in each iteration, slowing down the code
Dont worry about it. Unless you need to do thousands/millions of iterations and the script takes an unreasonably long time to complete, you shouldn't concern with negligible optimization gains.
That said, I'd use something like this:
if __name__ == '__main__':
def my_func(k):
return f'a{k}', f'b{k}'
keys = ['x', 'y', 'z']
results = (my_func(k) for k in keys)
grouped_values = zip(*results)
da, db = [dict(zip(keys, v)) for v in grouped_values]
print(da)
print(db)
# Output:
# {'x': 'ax', 'y': 'ay', 'z': 'az'}
# {'x': 'bx', 'y': 'by', 'z': 'bz'}
You cannot create two dicts in one dict comprehension.
If your primary goal is to just call my_func once to create both dicts, use a function for that:
def mkdicts(keys):
dict_of_a = {}
dict_of_b = {}
for key in keys:
dict_of_a[key], dict_of_b[key] = my_func(key)
return dict_of_a, dict_of_b
Let's say I have a dictionary:
data = {'a':1, 'b':2, 'c': 3, 'd': 3}
I want to get the maximum value(s) in the dictionary. So far, I have been just doing:
max(zip(data.values(), data.keys()))[1]
but I'm aware that I could be missing another max value. What would be the most efficient way to approach this?
Based on your example, it seems like you're looking for the key(s) which map to the maximum value. You could use a list comprehension:
[k for k, v in data.items() if v == max(data.values())]
# ['c', 'd']
If you have a large dictionary, break this into two lines to avoid calculating max for as many items as you have:
mx = max(data.values())
[k for k, v in data.items() if v == mx]
In Python 2.x you will need .iteritems().
You could try collecting reverse value -> key pairs in a defaultdict, then output the values with the highest key:
from collections import defaultdict
def get_max_value(data):
d = defaultdict(list)
for key, value in data.items():
d[value].append(key)
return max(d.items())[1]
Which Outputs:
>>> get_max_value({'a':1, 'b':2, 'c': 3, 'd': 3})
['c', 'd']
>>> get_max_value({'a': 10, 'b': 10, 'c': 4, 'd': 5})
['a', 'b']
First of all, find what is the max value that occurs in the dictionary. If you are trying to create a list of all the max value(s), then try something like this:
data = {'a':1, 'b':2, 'c': 3, 'd': 3}
max_value = data.get(max(data))
list_num_max_value = []
for letter in data:
if data.get(letter) == max_value:
list_num_max_value.append(max_value)
print (list_num_max_value)
Please let me know if that's not what you are trying to do and I will guide you through the right process.
I have a Dictionary here:
dic = {'A':1, 'B':6, 'C':42, 'D':1, 'E':12}
and a list here:
lis = ['C', 'D', 'C', 'C', 'F']
What I'm trying to do is (also a requirement of the homework) to check whether the values in the lis matches the key in dic, if so then it increment by 1 (for example there's 3 'C's in the lis then in the output of dic 'C' should be 45). If not, then we create a new item in the dic and set the value to 1.
So the example output should be look like this:
dic = {'A':1, 'B':6, 'C':45, 'D':2, 'E':12, 'F':1}
Here's what my code is:
def addToInventory(dic, lis):
for k,v in dic.items():
for i in lis:
if i == k:
dic[k] += 1
else:
dic[i] = 1
return dic
and execute by this code:
dic = addToInventory(dic,lis)
It compiles without error but the output is strange, it added the missing F into the dic but didn't update the values correctly.
dic = {'A':1, 'B':6, 'C':1, 'D':1, 'E':12, 'F':1}
What am I missing here?
There's no need to iterate over a dictionary when it supports random lookup. You can use if x in dict to do this. Furthermore, you'd need your return statement outside the loop.
Try, instead:
def addToInventory(dic, lis):
for i in lis:
if i in dic:
dic[i] += 1
else:
dic[i] = 1
return dic
out = addToInventory(dic, lis)
print(out)
{'A': 1, 'B': 6, 'C': 45, 'D': 2, 'E': 12, 'F': 1}
As Harvey suggested, you can shorten the function a little by making use of dict.get.
def addToInventory(dic, lis):
for i in lis:
dic[i] = dic.get(i, 0) + 1
return dic
The dic.get function takes two parameters - the key, and a default value to be passed if the value associated with that key does not already exist.
If your professor allows the use of libraries, you can use the collections.Counter data structure, it's meant precisely for keeping counts.
from collections import Counter
c = Counter(dic)
for i in lis:
c[i] += 1
print(dict(c))
{'A': 1, 'B': 6, 'C': 45, 'D': 2, 'E': 12, 'F': 1}