python dictionary adding to an existing key - python

I am trying to add items to a dictionary. I have already tried many of the things that have been suggested but nothing seems to be working.
This is my current version of the code.
For key "1", there will be three entries. But as I go through a list and try adding items to key '1", it simply replaces the value not append.

Try following:
>>> d = {}
>>> d.setdefault('1', []).append('x')
>>> d.setdefault('1', []).append('y')
>>> d.setdefault('1', []).append('z')
>>> d
{'1': ['x', 'y', 'z']}
or using collections.defaultdict:
>>> from collections import defaultdict
>>> d = defaultdict(list)
>>> d['1'].append('x')
>>> d['1'].append('y')
>>> d['1'].append('z')
>>> d
defaultdict(<type 'list'>, {'1': ['x', 'y', 'z']})

Related

Make a tree structure from a path name

This might be very simple, but I'm not sure what to do here.
In Python, I want to go through a list like:
full_list = ["A/A/A", "A/A/B", "B/B/B", "A/C/B"]
and get a dictionary with a kind of tree structure based on these labels, like this:
dictionary = {"A:{"A":["A", "B"], "C":["B"]},"B":{"B":["B]}}
but I'm not sure how to do it. I realize that I need some nested for loops. I know about the split() function in Python.
You can use recursion with collections.defaultdict:
from collections import defaultdict
def to_tree(data):
d = defaultdict(list)
for a, *b in data:
d[a].append(b)
return {a:[i for [i] in b] if all(len(i) == 1 for i in b) else to_tree(b)
for a, b in d.items()}
full_list = ["A/A/A", "A/A/B", "B/B/B", "A/C/B"]
result = to_tree([i.split('/') for i in full_list])
Output:
{'A': {'A': ['A', 'B'], 'C': ['B']}, 'B': {'B': ['B']}}
Making the leaf nodes list entries instead of empty dictionaries makes this trickier IMO -- I'd rethink that aspect of it.
>>> full_list = ["A/A/A", "A/A/B", "B/B/B", "A/C/B"]
>>> from collections import defaultdict
>>> dictionary = defaultdict(lambda: defaultdict(list))
>>> for entry in full_list:
... node = dictionary
... for path in entry.split("/"):
... if isinstance(node, dict):
... node = node[path]
... else:
... node.append(path)
...
>>> dictionary
defaultdict(<function <lambda> at 0x000001C8098171F0>, {'A': defaultdict(<class 'list'>, {'A': ['A', 'B'], 'C': ['B']}), 'B': defaultdict(<class 'list'>, {'B': ['B']})})

Dictionary Comprehension in Python for key:[1,2,3] [duplicate]

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']})

Instead of read a dictionary by keys, read by values (mydict[key] = value >>> mydict[value] = key) [duplicate]

This question already has answers here:
Reverse / invert a dictionary mapping
(32 answers)
Closed 5 years ago.
This question could sound something stange, but normally you can get values by the key, e.g:
>>> mydict = {'a':1,'b':2,'c':3}
>>> mydict['a']
1
>>> mydict['b']
2
>>> mydict['c']
3
But I need to do:
>>> mydict[1]
'a'
>>> mydict[2]
'b'
>>> mydict[3]
'c'
# In this case, my dictionary have to work like
>>> mydict = {1:'a',2:'b',3:'c'}
In my program my dictionary could be open by the two ways, I mean:
>>> mydict = {'a':1,'b':2,'c':3}
# Sometimes I need the value of a letter:
>>> mydict['a']
1
# And somethimes, I need the letter of a value.
>>> mydict.REVERSAL[1]
a
I can do something like: (I don't know if this work, I don't test it)
>>> mydict = {'a':1,'b':2,'c':3}
>>> mydict['a']
1
# etc...
>>> def reversal(z):
... tmp = {}
... for x,y in z.items():
... tmp[y] = x
... return tmp
>>> mydict = reversal(mydict)
>>> mydict[1]
a
# etc
>>> mydict = reversal(mydict)
>>> mydict['c']
3
# etc, etc, etc...
Is there an easy way to do that?
FIRST: I know about chr() and ord(), my code isn't about letters... this is only and example.
SECOND: In my dictionary there won't be two same values, so there won't be any problems with duplicate keys...
You need something like this,
In [21]: mydict = {'a':1,'b':2,'c':3}
In [22]: dict(zip(mydict.values(),mydict.keys()))
Out[22]: {1: 'a', 2: 'b', 3: 'c'}
Or
In [23]: dict(i[::-1] for i in mydict.items())
Out[23]: {1: 'a', 2: 'b', 3: 'c'}
Or
In [24]: dict(map(lambda x:x[::-1],mydict.items()))
Out[24]: {1: 'a', 2: 'b', 3: 'c'}
To reverse your dictionary, you can use .items():
mydict = {'a':1,'b':2,'c':3}
new_dict = {b:a for a, b in mydict.items()}
You can use some dictionary comprehension to switch keys and values:
>>> mydict = {'a': 1, 'b': 2, 'c': 3}
>>> reversal = {v: k for k, v in mydict.items()}
>>> reversal[1]
'a'

What is the best way to search for a key in multiple dictionaries in Python

I know we can search for a key in Python like this:
if key in myDict:
#Do something here
I know we can extend this and search for the key in multiple dictionaries using elif statement
if key in myDict_1:
#Do something here
elif key in myDict_2:
#Do something here
or by doing
if key in (myDict_1.keys() + myDict_2.keys()):
#Do something here
But is there a more succinct way to search for key in Python in two different dicts without using if-else or adding the list of keys explicitly ?
The answer to your question as written is:
if any(key in d for d in dicts):
# do something
If you need to know which dictionary or dictionaries contain the key, you can use itertools.compress():
>>> d1 = dict(zip("kapow", "squee"))
>>> d2 = dict(zip("bar", "foo"))
>>> d3 = dict(zip("xyz", "abc"))
>>> dicts = d1, d2, d3
>>> from pprint import pprint
>>> pprint(dicts)
({'a': 'q', 'k': 's', 'o': 'e', 'p': 'u', 'w': 'e'},
{'a': 'o', 'b': 'f', 'r': 'o'},
{'x': 'a', 'y': 'b', 'z': 'c'})
>>> from itertools import compress
>>> for d_with_key in compress(dicts, ("a" in d for d in dicts)):
... print(d_with_key)
...
{'a': 'q', 'p': 'u', 'k': 's', 'w': 'e', 'o': 'e'}
{'a': 'o', 'r': 'o', 'b': 'f'}
The correct way would be as Zero wrote:
if any(key in d for d in dicts): # do something
Fixing after reading comments below, thanks to #jwodder:
But you can also create a tuple of the keys of both (or more) dictionaries using the itertools.chain function.
>>> a = {1:2}
>>> b = {3:4}
>>> c = {5:6, 7:8}
>>> print(tuple(itertools.chain(a, b, c)))
(1, 3, 5, 7)
so you also can :
if x in tuple(itertools.chain(a, b, c)):
# Do something
A little list comprehension is also possible here; if you're simply trying to ascertain if a key is in a container of dicts, any() does exactly that; if you want to get the dict (or dicts) back and work with them, perhaps something like this would suffice:
>>> def get_dicts_with_key(some_key, *dicts):
... return [d for d in dicts if some_key in d]
>>> dict1 = {"hey":123}
>>> dict2 = {"wait":456}
>>> get_dicts_with_key('hey', dict1, dict2)
[{'hey': 123}]
>>> get_dicts_with_key('wait', dict1, dict2)
[{'wait': 456}]
>>> get_dicts_with_key('complaint', dict1, dict2)
[]
If the keys were present in either dict, both would be returned, as such:
>>> dict1['complaint'] = 777
>>> dict2['complaint'] = 888
>>> get_dicts_with_key('complaint', dict1, dict2)
[{'complaint': 777, 'hey': 123}, {'complaint': 888, 'wait': 456}]
>>>
Why don't you put your dicts in an iterable like a list and simple loop over then? You can express it as a function like so.
def has_key(key, my_dicts):
for my_dict in my_dicts:
if key in my_dict:
return True
return False
It would be used like so.
>>> dict1 = {'a':1, 'b': 2}
>>> dict2 = {'b':10, 'c': 11}
>>> has_key('b', [dict1, dict2])
True

Adding Items to Python Dictionary

I may have understood this wrong but looking at the examples found in "Learning Python" by O'Reilly I tried to do the following:
>>> d={}
>>> d['h']='GG'
>>> d['f']='JJ'
>>> d['h']='PP'
>>> print d
{'h': 'PP', 'f': 'JJ'}
Now instead of the 'key' 'h' having two entries 'GG' and 'PP' it only has the last entry, the last one replacing the first one.
I want BOTH in the same key.
>>> d['h']+='RR'
>>> print d
{'h': 'PPRR', 'f': 'JJ'}
Again this doesn't work, what I wanted was not a concatenated string but comma-separated entires.
I am confused why this does not work.
Your use-case is handled nicely by the collections.defaultdict() type instead:
>>> from collections import defaultdict
>>> d = defaultdict(list)
>>> d['h'].append('GG')
>>> d['f'].append('JJ')
>>> d['h'].append('PP')
>>> d
defaultdict(<type 'list'>, {'h': ['GG', 'PP'], 'f': ['JJ']})
A regular dictionary maps one key to one value, if you want that value to be a list, then you should make it a list, and append to the list instead.
You don't have to use a defaultdict() object, you can always make your values explicit lists:
>>> d = {}
>>> d['h'] = ['GG']
>>> d['f'] = ['JJ']
>>> d['h'].append('PP')
>>> print d
{'h': ['GG', 'PP'], 'f': ['JJ']}
but now you need to create the lists explicitly. The latter problem can then be circumvented again by using dict.setdefault():
>>> d = {}
>>> d.setdefault('h', []).append('GG')
>>> d.setdefault('f', []).append('JJ')
>>> d.setdefault('h', []).append('PP')
which is just a more verbose way of using what defaultdict() objects can provide directly.
It sounds like you want your dictionary to have 'h' map to a list of strings, which you can do as follows:
>>> d={}
>>> d['f']='JJ'
>>> d['h']=['PP']
>>> d['h'].append( 'RR' )
>>> d
{'h': ['PP', 'RR'], 'f': 'JJ'}
If you want all the keys of your dictionary to map to a list (instead of just 'h'), you can use collection.defaultdict as demonstrated in #MartijnPieters's answer.

Categories