Adding Items to Python Dictionary - python

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.

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

how to add to a dictionary using user input

I'm doing a project but there's one problem I've run into while using the dictionary, more specifically how to add an entry
thing = {'a':1, 'b':2, 'c':3}
thing.update(input('add more'))
print(thing)
The problem I get when I try to add to this is:ValueError: dictionary update sequence element #0 has length 1; 2 is required. So what way do I have to put the information in so that the dictionary gets updated? So far I tried "d [4]", "d 4" and "d:4".
You must convert your input to be a dictionary by using the curly braces ({ }). You can split the input so that you have a string that contains your key and a string that contains your value.
For example if you wanted to add the string input which was assigned the value d:4 you would use:
key, val = your_input.split(':')
thing.update({key:val})
This is because the dict.update function requires a dictionary as a parameter.
You haven't described what is acceptable for the user to enter, however, you can do it with ast.literal_eval(). This requires the user to enter a valid Python dictionary.
>>> from ast import literal_eval
>>> thing = {'a':1, 'b':2, 'c':3}
>>> thing.update(literal_eval(input('add more: ')))
add more: {'d':4, 'e':5, 'z':26}
>>> thing
{'a': 1, 'c': 3, 'z': 26, 'd': 4, 'b': 2, 'e': 5}
The input is not very user friendly though.
You could just have the user enter space separated keys and values, e.g. a 1 e 5 z 26. Then convert that to a dict and perform the update:
>>> thing = {'a':1, 'b':2, 'c':3}
>>> it = iter(input('add more: ').split())
add more: a 10 y 25
>>> thing.update(dict(zip(it, it)))
>>> thing
{'y': '25', 'c': 3, 'b': 2, 'a': '10'}
Or you could use : to separate keys and values, with space between each item:
>>> thing = {'a':1, 'b':2, 'c':3}
>>> thing.update(dict(s.split(':') for s in input('add more: ').split()))
add more: a:10 z:26
>>> thing
{'a': '10', 'c': 3, 'z': '26', 'b': 2}
If your goal is to add a single element, you can do something like this:
thing['d'] = 4
Substitute the input in the suitable place.
dictionary = {'Big brother':'Onii-chan', 'Big sister': 'Onee-sama', 'Hello': 'Konichiwa', 'Master': 'Sensei', 'Good Morning': 'Ohayo', 'Senior': 'Senpai', 'Ocean': 'Kaiyou/Umi','Darkness': 'Yami', 'Light': 'Hikari', 'Sky':'Sora','x':[1,2]}
keep_going = 'Y'
while keep_going == 'y' or keep_going == 'Y':
print(dictionary.keys())
x = input("Pick one out of the list to see the translation in japanese")
print(dictionary[x])
keep_going = input('would you like another one? (Y for Yes): ')

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

How to split two times?

I have a long string with some data… I need to split it by & and then each of it by = and create from it pair like key: value from the last split… Is it possible to do without big loops? Something like:
video_data = video_data.split('&')
video_data = {key:value for value.split('=') in video_data.iteritems()}
It looks like you're trying to parse a query string. Python already has a method for this, and that will also handle multiple values for keys and automatically create a dict of key->list of values for you:
from urlparse import parse_qs
s = 'a=3&b=5&a=4'
qs = parse_qs(s)
# {'a': ['3', '4'], 'b': ['5']}
As noted by J.F. Sebastian in comments:
Note: it does more than just splits on & and = e.g :
parse_qs("a=%21&b=urlencoded")
# {'a': ['!'], 'b': ['urlencoded']}
Either urlparse.parse_qs() or urlparse.parse_qsl() would do this job for you, better, faster and more robustly:
>>> example = 'foo=bar&ham=eggs&answer=42'
>>> from urlparse import parse_qs, parse_qsl
>>> parse_qs(example)
{'answer': ['42'], 'foo': ['bar'], 'ham': ['eggs']}
>>> parse_qsl(example)
[('foo', 'bar'), ('ham', 'eggs'), ('answer', '42')]
>>> dict(parse_qsl(example))
{'answer': '42', 'foo': 'bar', 'ham': 'eggs'}
Use one or the other depending on how much you need to support keys appearing multiple times in the query string.
But you really wanted to do this yourself with a dict comprehension, you need to nest the .split() call into a tuple:
video_data = {key: value for item in video_data.split('&') for key, value in (item.split('='),)}
but the same parse is just easier without a dict comprehension; using a generator expression instead to produce a sequence of key-value pairs for the dict() factory instead:
video_data = dict(item.split('=') for item in video_data.split('&'))
Demo:
>>> example = 'foo=bar&ham=eggs&answer=42'
>>> {key: value for item in example.split('&') for key, value in (item.split('='),)}
{'answer': '42', 'foo': 'bar', 'ham': 'eggs'}
>>> dict(item.split('=') for item in example.split('&'))
{'answer': '42', 'foo': 'bar', 'ham': 'eggs'}

python dictionary adding to an existing key

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

Categories