I have a dictionary which looks like:
dict = {'A':[1,2], 'B':[0], 'c':[4]}
need it to look like:
dict = {'A':[1,2], 'B':[0,0], 'c':[4,0]}
What I am doing right now:
dict = {x: y+[0] for (x,y) in dict.items() if len(y) < 2}
which generates:
dict = {'B':[0,0], 'c':[4,0]}
any idea how I could avoid eliminating those who do not meet the condition?
You're almost there. Try:
my_dict = {x: y + [0] if len(y) < 2 else y
for (x,y) in dict.items()}
(as mentioned by jp_data_analysis, avoid naming variables after builtins like dict)
This is one way.
Note: do not name variables after classes, e.g. use d instead of dict.
d = {'A':[1,2], 'B':[0], 'c':[4]}
d = {k: v if len(v)==2 else v+[0] for k, v in d.items()}
# {'A': [1, 2], 'B': [0, 0], 'c': [4, 0]}
You can use dictionary comprehension:
d = {'A':[1,2], 'B':[0], 'c':[4]}
new_d = {a:b+[0] if len(b) == 1 else b for a, b in d.items()}
Also, it is best practice not to assign variables to names shadowing common builtins, such as dict, as you are then overriding the function in the current namespace.
Your code is almost correct. Your problem is that you're filtering out any lists bigger than 2. What you need to do instead is simply place them in the new dictionary unchanged. This can be done using the ternary operator. It has the form value1 if condition else value2.
Also, if you want a more general way to pad every list in your dictionary to
be of equal length, you can use map and max.
Here is your code with the above modifications:
>>> d = {'A':[1, 2], 'B': [0], 'c': [4]}
>>>
>>> max_len = max(map(len, d.values()))
>>> {k: v + [0] * (max_len - len(v)) if len(v) < max_len else v for k, v in d.items()}
{'A': [1, 2], 'B': [0, 0], 'c': [4, 0]}
>>>
A generalized way:
d = {'A':[1,2], 'B':[0], 'c':[4]}
m = max(len(v) for v in d.values())
for k, v in d.items():
if len(v) < m:
d[k].extend([0 for i in range(m-len(v))])
You were very close, just use update():
d = {'A':[1,2], 'B':[0], 'c':[4]}
d.update({x: y+[0] for (x,y) in d.items() if len(y) < 2})
d
# {'A': [1, 2], 'B': [0, 0], 'c': [4, 0]}
Like others have said, don't use reassign reserved names like dict, it's a one way street down to debugging hell.
Related
Is there a better/pythonic way to do the following:
I have a function that merges dictionaries:
def merge_dicts(a, *dict_args):
for dictionary in dict_args:
for k, v in dictionary.items():
if k not in a:
a[k] = v
return a
Here is a sample run:
a = {'A': 1, 'B': 2}
b = {'B': 3, 'C': 4}
c = merge_dicts(a, b) # {'A': 1, 'B': 2, 'C': 4}
I am using python2.7.
You can use update. Since the earlier dicts have priority you have to update in reverse order, and update with a last:
def merge_dicts(a, *dict_args):
d = {}
for dictionary in reversed(dict_args):
d.update(dictionary)
d.update(a)
return d
Or as a one-liner, using itertools.chain:
from itertools import chain
def merge_dicts(a, *dict_args):
# chain (key, value) items in order of increasing priority
return dict(chain.from_iterable(d.iteritems() for d in dict_args[::-1]+(a,)))
> merge_dicts(a, b)
{'A': 1, 'C': 4, 'B': 2}
If I may add, why not remove a from the function signature altogether:
def merge_dicts(*dict_args):
return dict(chain.from_iterable(d.iteritems() for d in dict_args[::-1]))
# If you provide 0 or 1 dict,
# this will return an empty dict or the single dict (a copy thereof) itself
You don't need to check the existence of keys in dictionaries, since you want to preserve the first key you can use a dict comprehension by looping through the list of dictionaries backward:
{k: v for d in list_of_dict[::-1] for k, v in d.items()}
Python will replace the existence keys with new ones, each time it encounter a duplicate one, and since you are looping through the list backward, it will comes up with the first keys in your aggregated dictionary.
Based on your example:
>>> {k: v for d in l[::-1] for k, v in d.items()}
{'A': 1, 'C': 4, 'B': 2}
I have a defaultdict of lists, but I want to basically do this:
myDefaultDict = filter(lambda k: len(k)>1, myDefaultDict)
Except it only seems to work with lists. What can I do?
Are you trying to get only values with len > 1?
Dictionary comprehensions are a good way to handle this:
reduced_d = {k: v for k, v in myDefaultDict.items() if len(v) > 1}
As martineau pointed out, this does not give you the same defaultdict functionality of the source myDefaultDict. You can use the dict comprehension on defaultdict instantiaion, as martineau shows to get the same defaultdict functionality.
from collections import defaultdict
myDefaultDict = defaultdict(list, {'ab': [1,2,3], 'c': [4], 'def': [5,6]}) # original
reduced_d = defaultdict(list, {k: v for k, v in myDefaultDict.items() if len(v) > 1})
I'm not sure whether you want to delete keys or values longer than 1.
Assuming it's the length of the key, here's how to do it with filter:
from collections import defaultdict
# create test data
my_defaultdict = defaultdict(list, {'ab': [1,2,3], 'c': [4], 'def': [5,6]})
my_defaultdict = defaultdict(my_defaultdict.default_factory,
filter(lambda i: len(i[0])>1, my_defaultdict.items()))
print(my_defaultdict)
Output:
defaultdict(<type 'list'>, {'ab': [1, 2, 3], 'def': [5, 6]})
If it's the length of the associated value, just change the len(i[0]) to len(i[1]).
You can use filter and then use map to remove each dict entry based on the filtered condition:
>>> example={'l1':[1], 'l2':[2,3], 'l3':[4,5,6], 'l4':[7]}
>>> filter(lambda k: len(example[k])<2, example)
['l4', 'l1']
>>> map(example.__delitem__, filter(lambda k: len(example[k])<2, example))
[None, None]
>>> example
{'l2': [2, 3], 'l3': [4, 5, 6]}
This question already has answers here:
Inverse dictionary lookup in Python
(13 answers)
Closed 7 years ago.
>>>Dictionary[key]
The above statement returns the first corresponding value of the 'key' from the 'Dictionary' but is there a function that does the opposite, i.e. search for the key by it's value
You can write simple lambda for this:
d={"a":5, "bf": 55, "asf": 55}
search_key = lambda in_d, val: (k for k,v in in_d.items() if v == val)
for k in search_key(d, 55):
print(k)
# since the lambda returns generator expression you can simply print
# the keys as follows:
print(list(search_key(d, 55)))
# or get the key list
key_list = list(search_key(d, 55))
Gives:
asf
bf
Just iterate over the dictionary items and check for the value with your string. If it matches then print it's corresponding key.
>>> d = {'foo':1,'bar':2}
>>> for k,v in d.items():
if v == 1:
print(k)
foo
There's no single function, but it's easy to get the (possibly multiple) keys for a particular value:
>>> d = {'a': 0, 'b': 1, 'c': 2, 'd': 3, 'e': 4, 'f': 0, 'g': 1}
>>> [k for k, v in d.items() if v == 1]
['b', 'g']
i don't think you can, but you can do this
In [3]: dict_1 = {1:"one", 2:"two"}
In [4]: for number, alphabet in dict_1.items():
...: if alphabet == "two":
...: print number
...:
Trivial, using list comprehensions:
>>> d = {'a': 1, 'b': 2, 'c': 1}
>>> l = [k for k, v in d.items() if v == 1]
>>> l
['c', 'a']
For this you can work with .keys() and .values(), which will return a list of keys or values respectivley. These lists can be easily iterated over and searched.
An example with a simple dictionary:
>>> D1 = {'A':1, 'B':2, 'C':1}
>>> D1['A']
1
>>> for key in D1.keys():
if D1[key] == 1:
print(key)
C
A
As Padraic Cunningham pointed out, a key must be unique, but a value does not, so you run into problems when you have multiple keys that match 1 value.
Perhaps it's too straightforward...
def val2key(dict, val):
for k, v in dict.items():
if v == val:
return k
return None
Use a list comprehension and substitute the name of your dictionary and the desired value.
keys = [k for k, v in my_dict.items() if v == my_value]
Lets have a following dict:
table = {x1: {y1: 1, y2:2},
x2: {y1: 3, y2:4},
x3: {y3: 5, y2:6}
}
Considering the values are unique, is there any way to query the key path based on the value efficiently or it is better to reconstruct the dict using the value as the key?
Example:
result = magic_function(table, 3)
result --> [x2, y1]
Thanks,
The idiomatic way to "invert" a dictionary is like this:
i = {v: k for (k, v) in d.items()}
If you're in Python 2 rather than 3, and d might be big, use iteritems instead.
In your case, you've got a dict of dicts, and you want to sort of double-invert it into a dict of paths, if I understand correctly. But you don't know how to write that. So, let's start by writing it explicitly, the long way:
i = {}
for k, v in d.items():
for k2, v2 in v.items():
i[v2] = (k, k2)
You can convert this into a dictionary comprehension, but you want it to be something you actually understand, rather than some magic invocation you copy and paste without thinking, so I'll leave that part up to you (but I'll be glad to help if you have any questions).
Inverting is probably the better way to go:
In [17]: d = {table[k1][k2]: (k1,k2) for k1 in table for k2 in table[k1]}
Here's a solution handling arbitrary depth and "ragged" dicts:
def invert_arbitrary(d, ldict, p=[]):
for k, v in ldict.items():
if isinstance(v, dict):
invert_arbitrary(d, v, p + [k])
else:
d[v] = p + [k]
Example:
table = {'x1': {'y1': 1, 'y2': 2},
'x2': {'y1': 3,
'y2': {'z1': 4, 'z2': 5}},
'x3': 6}
In [40]: d = dict()
In [41]: invert_arbitrary(d, table)
In [42]: d
Out[42]:
{1: ['x1', 'y1'],
2: ['x1', 'y2'],
3: ['x2', 'y1'],
4: ['x2', 'y2', 'z1'],
5: ['x2', 'y2', 'z2'],
6: ['x3']}
Code goes below:
d = {'a':0, 'b':0, 'c':0, 'd':0} #at the beginning, all the values are 0.
s = 'cbad' #a string
indices = map(s.index, d.keys()) #get every key's index in s, i.e., a-2, b-1, c-0, d-3
#then set the values to keys' index
d = dict(zip(d.keys(), indices)) #this is how I do it, any better way?
print d #{'a':2, 'c':0, 'b':1, 'd':3}
Any other way to do that?
PS. the code above is just a simple one to demonstrate my question.
Something like this might make your code more readable:
dict([(x,y) for y,x in enumerate('cbad')])
But you should give more details what you really want to do. Your code will probably fail if the characters in s do not fit the keys of d. So d is just a container for the keys and the values are not important. Why not start with a list in that case?
use update() method of dict:
d.update((k,s.index(k)) for k in d.iterkeys())
What about
d = {'a':0, 'b':0, 'c':0, 'd':0}
s = 'cbad'
for k in d.iterkeys():
d[k] = s.index(k)
? It's no functional programming anymore but should be more performant and more pythonic, perhaps :-).
EDIT: A function variant using python dict-comprehensions (needs Python 2.7+ or 3+):
d.update({k : s.index(k) for k in d.iterkeys()})
or even
{k : s.index(k) for k in d.iterkeys()}
if a new dict is okay!
for k in d.iterkeys():
d[k] = s.index[k]
Or, if you don't already know the letters in the string:
d = {}
for i in range(len(s)):
d[s[i]]=i
another one liner:
dict([(k,s.index(k)) for (k,v) in d.items()])
You don't need to pass a list of tuples to dict. Instead, you can use a dictionary comprehension with enumerate:
s = 'cbad'
d = {v: k for k, v in enumerate(s)}
If you need to process the intermediary steps, including initial setting of values, you can use:
d = dict.fromkeys('abcd', 0)
s = 'cbad'
indices = {v: k for k, v in enumerate(s)}
d = {k: indices[k] for k in d} # dictionary comprehension
d = dict(zip(d, map(indices.get, d))) # dict + zip alternative
print(d)
# {'a': 2, 'b': 1, 'c': 0, 'd': 3}
You choose the right way but think that no need to create dict and then modify it if you have ability to do this in the same time:
keys = ['a','b','c','d']
strK = 'bcad'
res = dict(zip(keys, (strK.index(i) for i in keys)))
Dict comprehension for python 2.7 and above
{key : indice for key, indice in zip(d.keys(), map(s.index, d.keys()))}
>>> d = {'a':0, 'b':0, 'c':0, 'd':0}
>>> s = 'cbad'
>>> for x in d:
d[x]=s.find(x)
>>> d
{'a': 2, 'c': 0, 'b': 1, 'd': 3}