setting multiple keys/values into a dictionary (python 2.72) - python

I have a list of strings. I am willing to create a dictionary which its keys are all the strings in the list (each string is a key of course).
Now for the values: The value corresponding to each key will be the string which comes next after the key string on the list. The values will be from list type.
Remarks: The last word won't be included in the dictionary.
a key won't appear twice on the dic. if there are more than one values for a certain key, they will be added to the exist value's list of the key.
The order doesn't matter (the dictionary can be not sorted if it makes the job easier).
Example:
for the list:
List = ['today','is','worm','and','dry']
the dictionary will be:
Dic={'today': ['is'], 'is': ['worm'],'worm': ['and'], 'and':['dry']}
Thanks,

l = ['today','is','worm','and','dry']
d = {}
for w1, w2 in zip(l, l[1:]):
d.setdefault(w1, []).append(w2)
# d == {'and': ['dry'], 'is': ['worm'], 'today': ['is'], 'worm': ['and']}

Not very fine but it is working
>>> List = ['today','is','worm','and','dry']
>>> Dic ={}
>>> key = None
>>> for item in List:
... if key:
... Dic.update({key:item})
... key=item
...
>>> Dic
{'and': 'dry', 'is': 'worm', 'worm': 'and', 'today': 'is'}
>>>

(based on #eumiro's answer)
>>> l = ['today','is','worm','and','dry']
>>> print dict(zip(l, l[1:]))
{'and': 'dry', 'is': 'worm', 'worm': 'and', 'today': 'is'}
>>> print dict(zip(l, l[1:] + [None]))
{'and': 'dry', 'dry': None, 'is': 'worm', 'worm': 'and', 'today': 'is'}
>>> print dict((k, [v]) for (k, v) in zip(l, l[1:] + [None]))
{'and': ['dry'], 'dry': [None], 'is': ['worm'], 'worm': ['and'], 'today': ['is']}

Try this:
lst = ['today','is','worm','and','dry']
dic = {}
for k in xrange(len(lst) - 1):
dic[lst[k]] = [lst[k+1]]
It's an efficient answer, since it doesn't create any additional lists for building the dictionary. You can check the result, it's what was expected:
dic == {'today': ['is'], 'is': ['worm'],'worm': ['and'], 'and':['dry']}
> True

You can achieve it by the following code:
Dic = dict((key, [item]) for key, item in zip(List, List[1:]))
and the result will be the following:
>>> Dic
{'and': ['dry'], 'is': ['worm'], 'worm': ['and'], 'today': ['is']}
If you need more performant solution, you can use izip() function:
from itertools import izip
Dic = dict((key, [item]) for key, item in izip(List, List[1:]))
which will give the same result, but in a more efficient way.
But please follow naming conventions for Python (eg. call your variables my_dict and my_list, but preferably give them more meaningful names) and do not overwrite list and dict keywords (that is in case you would like to give your variables such names).

Related

Case Insensitive Dictionary Iteration

I have a dictionary which has peoples' first names as keys. Each name has a capitalised first letter (James, Ben, John, etc).
I use list comprehension to check if any keys are in a string:
[val for key, val in name_dict.items() if key in new_message]
The issue is that sometimes the names appear in new_message without capitalised first letters (james, ben, john, etc). I could add these variations to the dictionary but that sould invovle a lot of work.
Is there a simple way to iterate over the dictionary keys in a case insensitive way?
Use title() on new_message, it will capitalize all the words in the string
new_message = 'James, ben, JOHN'
print(new_message.title()) # James, Ben, John
You can just lower the text while iterating,
new_message = [x.lower() for x in new_message]
[val for key, val in name_dict.items() if key.lower() in new_message]
( Assuming if the new_message is list, for string it will be just new_message.lower() )
This will make the comparison case-insensitive.
Full example
>>> new_message = ['John', 'JameS', 'BEN']
>>> name_dict = {'john': 1, 'Ben': 2, 'JaMES': 3}
>>>
>>> [x.lower() for x in new_message]
['john', 'james', 'ben']
>>> new_message = [x.lower() for x in new_message]
>>> [val for key, val in name_dict.items() if key.lower() in new_message]
[1, 2, 3]
>>>

Python: Create a dictionary where keys have multiple values

The problem that I have is hard to explain, easy to understand:
I have a list of tuples:
L=[('a','111'),('b','222'),('a','333'),('b','444')]
from this list I want to createa dictionary where the keys are the first elements of the tuples ('a' and 'b') and the values associated are in a list:
expected output:
{'a':['111','333'],'b':['222','444']}
How can I solve this problem?
d={}
for x in range (len(L)):
d[L[x][0]]=[L[x][1]]
return d
but as you can easy understand, the output won't be complete since the list will show just the last value associated to that key in L
You can use setdefault() to set the key in the dict the first time. Then append your value:
L=[('a','111'),('b','222'),('a','333'),('b','444')]
d = {}
for key, value in L:
d.setdefault(key, []).append(value)
print(d)
# {'a': ['111', '333'], 'b': ['222', '444']}
You have to append L[x][1] to an existing list, not replace whatever was there with a new singleton list.
d={}
for x in range (len(L)):
if L[x][0] not in d:
d[L[x][0]] = []
d[L[x][0]].append(L[x][1])
return d
A defaultdict makes this easier:
from collections import defaultdict
d = defaultdict(list)
for x in range(len(L)):
d[L[x][0]].append(L[x][1])
return d
A more idiomatic style of writing this would be to iterate directly over the list and unpack the key and value immediately:
d = defaultdict(list)
for key, value in L:
d[key].append(value)
You can try this:
L = [('a','111'),('b','222'),('a','333'),('b','444')]
my_dict = {}
for item in L:
if item[0] not in my_dict:
my_dict[item[0]] = []
my_dict[item[0]].append(item[1])
print(my_dict)
Output:
python your_script.py
{'a': ['111', '333'], 'b': ['222', '444']}
As pointed by #chepner, you can use defaultdict to.
Basically, with defaultdict you'll not need to check if there is no key yet in your dict.
So it would be:
L = [('a','111'),('b','222'),('a','333'),('b','444')]
my_dict = defaultdict(list)
for item in L:
my_dict[item[0]].append(item[1])
print(my_dict)
And the output:
defaultdict(<class 'list'>, {'a': ['111', '333'], 'b': ['222', '444']})
And if you want to get a dict from the defaultdict, you can simply create a new dict from it:
print(dict(my_dict))
And the output will be:
{'a': ['111', '333'], 'b': ['222', '444']}

How to create a dictionary that shows which values of another dictionary belong to which keys

I have the following dictionary: {26:['hello', 'test'], 27:['hello', 'good', 'morning', 'test']}
I need to create a new dictionary with as key the word and as value a list whith the keys in which it exists as a value, it should look like this: dict1 = {'hello':[26,27], 'test':[26,27], 'good':[27], 'morning':[27]}
To try to solve my problem, I already created a list with all the words without duplicates, so words = ['hello', 'test', 'good', 'morning']. Then I tried this:
newdict = {}
for i in words:
l = []
for k in dict1:
if i in dict1[k]:
l.append(k)
newdict[i] = l
Can you help me? Thanks in advance.
This is the inversion operation that turns {k:[v]} into {v:[k]}:
output = {}
for k,v in input.items():
for e in v:
output.setdefault(e, []).append(k)
Without imports you can do it like this:
a = {26:['hello', 'test'], 27:['hello', 'good', 'morning', 'test']}
result = {}
for k, v in a.items():
for item in v:
result[item] = result.get(item, []) + [k]
The dict. get(key[, default]) is explained here.
So, your result dict will either return it's value or empty list.
After that you can simply use + operator which is concatenation operator in case of lists.
Take note that list concatenation works only between lists, so we are wrapping the value in [] making it a list containing the key.
Using collections.defaultdict
Ex:
from collections import defaultdict
data = {26:['hello', 'test'], 27:['hello', 'good', 'morning', 'test']}
result = defaultdict(list)
for k, v in data.items():
for item in v:
result[item].append(k)
print(result)
Using setdefault
Ex:
result = {}
for k, v in data.items():
for item in v:
result.setdefault(item, []).append(k)
Output:
defaultdict(<type 'list'>, {'test': [26, 27], 'good': [27], 'hello': [26, 27], 'morning': [27]})
{'test': [26, 27], 'good': [27], 'hello': [26, 27], 'morning': [27]}

Count values with items in a dictionary with sublists

I'n being warned that this question has been frequently downvoted, but I haven't seen a solution for my particular problem.
I have a dictionary that looks like this:
d = {'a': [['I', 'said', 'that'], ['said', 'I']],
'b':[['she', 'is'], ['he', 'was']]}
I would like for the output to be a dictionary with the original keys and then a dictionary containing a value that indicates the count for each of the words (e.g., {'a':{'I':2, 'said':2, 'that':1} and so on with b.
If the values were in a list instead of a sublist, I could get what I wanted just by using Counter:
d2 = {'a': ['I','said','that', 'I'],'b': ['she','was','here']}
from collections import Counter
counts = {k: Counter(v) for k, v in d2.items()}
However, I'm getting TypeError: unhashable type: 'list' because the lists containing the values I want to count are sublists and the list that contains them isn't hashable.
I also know that if I just had sublists, I could get what I want with something like:
lst = [['I', 'said', 'that'], ['said', 'I']]
Counter(word for sublist in lst for word in sublist)
But I just can't figure out how to combine these ideas to solve my problem (and I guess it lies in combining these two).
I did try this
for key, values in d.items():
flat_list = [item for sublist in values for item in sublist]
new_dict = {key: flat_list}
counts = {k: Counter(v) for k, v in new_dict.items()}
But that only gives me the counts for the second list (because the flat_list itself only returns the value for the second key.
To combine the two solutions, just replace Counter(v) from your first solution with the second solution.
from collections import Counter
d = {'a': [['I', 'said', 'that'], ['said', 'I']],
'b': [['she', 'is'], ['he', 'was']]}
counts = {k: Counter(word
for sublist in lst
for word in sublist)
for k, lst in d.items()}
print(counts)
Output:
{'a': Counter({'I': 2, 'said': 2, 'that': 1}),
'b': Counter({'she': 1, 'is': 1, 'he': 1, 'was': 1})}
You can merge your sublists to get your d2: d2 = {k: reduce(list.__add__, d[k], []) for k in d}.
In python3, you will need to from functools import reduce
Use both itertools and collections modules for this. Flatten the nested lists with itertools.chain and count with collections.Counter
import itertools, collections
d = {
'a': [['I', 'said', 'that'], ['said', 'I']],
'b':[['she', 'is'], ['he', 'was']]
}
out_dict = {}
for d_key, data in d.items():
counter = collections.Counter(itertools.chain(*data))
out_dict[d_key] = counter
print out_dict
Output:
{'a': Counter({'I': 2, 'said': 2, 'that': 1}),
'b': Counter({'she': 1, 'is': 1, 'he': 1, 'was': 1})}

Best way to convert str 'key: value\r\nkey:value\r\n' to dict, python

I have the following string "first: 1\r\nsecond: 2\r\n", I want to receive following dict {'first': 1, 'second': 2}.
How can I do that?
You can use regular expressions:
import re
matches = re.findall(r'(\w+):\s*(\d+)', my_string)
# [('first', '1'), ('second', '2')]
matches = [(x[0], int(x[1])) for x in matches]
# [('first', 1), ('second', 2)]
d = dict(matches)
# {'first': 1, 'second': 2}
If you can guarantee that there is a space between the colon and the value, split by newlines, then split by whitespace, then convert to integer, then make a dictionary out of the result:
s = 'first: 1\r\nsecond: 2\r\n'
result = {k:int(v) for k,v in (item.split() for item in s.strip().split('\r\n'))}
Result:
>>> result
{'first:': 1, 'second:': 2}
If you're not guaranteed to have whitespace between the colon and the value, but you know that it's always a string not containing a colon for the key and an integer for the value, you could try a regular expression:
import re
s = 'first: 1\r\nsecond:2\r\n'
result = {k.strip():int(v) for k,v in re.findall(r'([^:]+):\s*(\d+)', s)}
Result:
>>> result
{'first': 1, 'second': 2}
You could use the split method with a for loop, though I doubt it's the most efficient way to do it :
def strToDict(string):
myDict = {}
for line in string.strip().split("\r\n"):
key, val = map(str.strip, line.split(": "))
myDict[key] = int(val)
return myDict
strToDict("first: 1\r\nsecond: 2\r\n") # {'first': 1, 'second': 2}

Categories