Related
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})}
This question already has answers here:
Grouping Python dictionary keys as a list and create a new dictionary with this list as a value
(2 answers)
Closed 4 years ago.
I have a list of dictionaries. How can i group that list by valaues.
list = [{a:1},{b:2},{c:1},{d:3},{e:2}]
Now my result should be like below
1:a,c
2:b,e
3:d
I tried using groupby from itertools. But i couldn't get the required result. I am using python 2.7.
Could you help me achieve this?
If you want to use groupby, the list has to be sorted by the same key you want to group by.
>>> lst = [{'a':1}, {'b':2}, {'c':1}, {'d':3}, {'e':2}]
>>> keyfunc = lambda d: next(iter(d.values()))
>>> sorted(lst, key=keyfunc)
[{'a': 1}, {'c': 1}, {'b': 2}, {'e': 2}, {'d': 3}]
>>> {k: [x for d in g for x in d]
... for k, g in itertools.groupby(sorted(lst, key=keyfunc), key=keyfunc)}
{1: ['a', 'c'], 2: ['b', 'e'], 3: ['d']}
Here's a possible solution without using any library.
def get_dict(list):
res = {}
for elem in list:
k, v = elem.keys(), elem.values()
if v[0] in res:
res[v[0]].append(k[0])
else:
res[v[0]] = [k[0]]
return res
With a list like yours, this would output a dictionary with the following format:
{ 1:[a,c], 2:[b, e], 3:[c] }
This is considering you're always going to have the same format as input. If not, you could just adjust what is read and saved.
This might help.
list = [{"a":1},{"b":2},{"c":1},{"d":3},{"e":2}]
d = {}
for i in list:
key, value = i.items()[0]
if value not in d:
d[value] = [key]
else:
d[value].append(key)
print(d)
Output:
{1: ['a', 'c'], 2: ['b', 'e'], 3: ['d']}
Tested in python2.7
Here is a way to do what you are looking for:
list_ = [{"a":1},{"b":2},{"c":1},{"d":3},{"e":2}]
values = set(value for dic in list_ for value in dic.values())
for value in values:
keys = [list(dic.keys())[0] for dic in list_ if value in dic.values()]
print("{}: {}".format(value, keys))
Output:
1: ['a', 'c']
2: ['b', 'e']
3: ['d']
Here's a solution that uses defaultdict.
from __future__ import print_function
from collections import defaultdict
lst = [{'a': 1}, {'b': 2}, {'c': 1}, {'d': 3}, {'e': 2}]
d = defaultdict(list)
for l in lst:
val, key = l.items()[0]
d[key].append(val)
print(d)
Output:
defaultdict(<type 'list'>, {1: ['a', 'c'], 2: ['b', 'e'], 3: ['d']})
I have a dictionary, what:
what = {'a': ['b'], 'c': ['d\n', 'e\n', 'f'], 'd': ['f', 'g']}
and need to get the items with '/n' separate and without '/n' (order is important, need to sort the values.):
[[{'a': ['b'], 'c': ['f'], 'd': ['f', 'g']}], [{'c': ['d\n', 'e\n']}]]
This is what I tried:
def lst(profiles_file: TextIO):
solve_lst = []
new_lst = fix_files(profiles_file)
for k, v in new_lst.items():
for i in v:
if i.find('\n') != -1:
get_index = [v.index(i)]
solve_lst.append(get_index)
return solve_lst
How can i get this without doing anything to complicated?
Here's a solution using defaultdict
from collections import defaultdict
def lst(profiles_file: TextIO):
initial_dict = fix_files(profiles_file)
with_n = defaultdict(list)
without_n = defaultdict(list)
for k, v in initial_dict.items():
for item in v:
if '\n' in item:
with_n[k].append(item)
else:
without_n[k].append(item)
return [without_n, with_n]
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}
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: