Group list of dictionaries by value [duplicate] - python

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

Related

How can I filter a dict list with subset of a dict? [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 1 year ago.
Improve this question
I am trying to find all dicts that include my prepared dict as a subset. I have a dict with 2 keys and I have 5 dicts in a list. I am trying to filter all dicts which includes my dict like this:
my_dict = {'A':'A','B':'B'}
all_dict = [{'A':'A','B':'B','C':'C'},{'A':'A','B':'B','C':'C','D':'D'},{'D':'D','E':'E'},{'A':'A','B':'B'},{'A':'A','D':'D'}]
result = []
for i in all_dict:
if my_dict in i:
result.append(i)
print(result)
#print output empty list
#output supposed to:
#{'A': 'A', 'B': 'B', 'C': 'C'}
#{'A': 'A', 'B': 'B', 'C': 'C', 'D': 'D'}
#{'A': 'A', 'B': 'B'}
According to my for loop, it appends if the dict exactly the same with iteration. How can I find all dicts include my_dict as a subset? What is your suggestions?
You can use list-comprehension, for each dictionary in the list, see if the my_dict's keys is the subset of the dictionary's key:
[each for each in all_dict if set(my_dict).issubset(each)]
#output:
[{'A': 'A', 'B': 'B', 'C': 'C'}, {'A': 'A', 'B': 'B', 'C': 'C', 'D': 'D'}, {'A': 'A', 'B': 'B'}]
Use the fact that dict.items() returns a set-like object that can be compared like so:
result = [x for x in all_dict if my_dict.items() <= x.items()]
You can define a function that tests whether a dictionary dict_1 is a subset of dict_2:
def is_subset(dict_1, dict_2):
for k, v in dict_1.items():
if k not in dict_2 or dict_2[k]!=v:
return False
return True
Your code then becomes:
my_dict = {'A':'A','B':'B'}
all_dict = [{'A':'A','B':'B','C':'C'},{'A':'A','B':'B','C':'C','D':'D'},{'D':'D','E':'E'},{'A':'A','B':'B'},{'A':'A','D':'D'}]
result = []
for i in all_dict:
if is_subset(my_dict, i):
result.append(i)
print(result)
Example without issubset().
Try using all()
result = [i for i in all_dict if all(grp in i.items() for grp in my_dict.items())]

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

Find top counted element in a dictionary of a dictionary

I have a dictionary of dictionary myDict:
myDict = { 'cow': {'A':2, 'B':5, 'C':3},
'cat': {'A':7, 'B':1, 'C':6},
'dog': {'A':1, 'B':4, 'C':3},
'bird': {'A':5, 'B':7, 'C':9}
}
I want to find the top count element for each animal in this case, i.e. the output should be:
myNewTable = {'cow':'B', 'cat':'A', 'dog':'B', 'bird':'C'}
I tried to achieve this using the following code:
myNewTable = max(x.items(), key=operator.itemgetter(1))[0] for x in myDict
but got the following error:
File "<ipython-input-11-3bcb909a6476>", line 28
myNewTable = max(x.items(), key=operator.itemgetter(1))[0] for x in myDict
^
SyntaxError: invalid syntax
What did I do wrong here ? And how could I fix this?
Well, your syntax is wrong, but you have the right idea. A nice and succinct solution using max and dict.get can be built on by iterating over myDict:
>>> {k : max(v, key=v.get) for k, v in myDict.items()}
{'bird': 'C', 'cat': 'A', 'cow': 'B', 'dog': 'B'}
You are using comprehension syntax but haven't wrapped it in a specific type (e.g. list => [], set => {}, dict => {:}). So fixing your code it would look like:
In []:
[max(myDict[x].items(), key=operator.itemgetter(1))[0] for x in myDict]
Out[]:
['B', 'A', 'B', 'C']
But you wanted it as a dict, so perhaps you meant:
In []:
{x: max(myDict[x].items(), key=operator.itemgetter(1))[0] for x in myDict}
Out[]:
{'bird': 'C', 'cat': 'A', 'cow': 'B', 'dog': 'B'}
But can be specified more succinctly (as per #coldspeed's answer):
{x: max(myDict[x], key=myDict[x].get) for x in myDict}
Another alternative using collections.Counter with its .most_common(...) method:
>>> from collections import Counter
>>> {k: Counter(v).most_common(1)[0][0] for k, v in myDict.items()}
{'cat': 'A', 'bird': 'C', 'cow': 'B', 'dog': 'B'}
This will be useful in general if you want to select more than one highest count elements from the nested dict. For example, below is the sample to select list of two most common keys in dict:
>>> {k: [x[0] for x in Counter(v).most_common(2)] for k, v in myDict.items()}
{'dog': ['B', 'C'], 'bird': ['C', 'B'], 'cat': ['A', 'C'], 'cow': ['B', 'C']}
From the Counter.most_common([n]) document:
Return a list of the n most common elements and their counts from the most common to the least. If n is omitted or None, most_common() returns all elements in the counter. Elements with equal counts are ordered arbitrarily:

How to join two dictionaries with overlapping key values in python?

For example if my dictionaries are,
dict1 = {1:'a',2:'b',3:'c'}
dict2 = {1:'d',2:'e'}
Then I want the joined dictionary to be,
{1:'a',2:'b',3:'c',4:'d',5:'e'}
Looks like you don't care about the keys at all. So just figure out what order you want to join the dictionaries in and do:
import itertools
ordered_dicts = [dict1, dict2] # N.B. normal dicts, not OrderedDicts!
ordered_values = [v for d in itertools.chain(ordered_dicts) for _, v in sorted(d.items())]
result = dict(zip(itertools.count(1), ordered_values))
Try this:
dict1 = {1:'a', 2:'b', 3:'c'}
dict2 = {1:'d', 2:'e'}
# Change the name of a key
# Note this will delete the keys 1 and 2 in dict2
dict2[4] = dict2.pop(1) # Return the corresponding value
dict2[5] = dict2.pop(2)
# Merging the two dicts (works in Python 3.5+)
result = {**dict1, **dict2}
>>> result
{1: 'a', 2: 'b', 3: 'c', 4: 'd', 5: 'e'}
Alternatively, if you want to keep dict2 unchanged:
dict1 = {1:'a', 2:'b', 3:'c'}
dict2 = {1:'d', 2:'e'}
for i, k in enumerate(dict2, start=len(dict1) + 1):
dict1[i] = dict2[k]
>>> dict1
{1: 'a', 2: 'b', 3: 'c', 4: 'd', 5: 'e'}
We can use Pandas:
import pandas as pd
dict1 = {1:'a',2:'b',3:'c'}
dict2 = {1:'d',2:'e'}
df1 = pd.DataFrame.from_dict(dict1, orient='index')
df2 = pd.DataFrame.from_dict(dict2, orient='index')
pd.concat([df1,df2]).set_axis(range(1,len(df1)+len(df2)+1), inplace=False).to_dict()[0]
Output:
{1: 'a', 2: 'b', 3: 'c', 4: 'd', 5: 'e'}
enumerate has a start keyword argument, you can count from whatever number you want. Here you can use it to solve your issue without importing any heavy external module or many loops:
dict1 = {1:'a',2:'b',3:'c'}
dict2 = {1:'d',2:'e'}
for index,values in enumerate(dict2.items(),start=len(dict1)+1):
dict1[index] = values[1]
print(dict1)
output:
{1: 'a', 2: 'b', 3: 'c', 4: 'd', 5: 'e'}
dict1 = {1:'a',2:'b',3:'c'}
dict2 = {1:'d',2:'e'}
d = {}
# creating a new dictionary same as dict1
for k,v in dict1.items():
d[k] = v
# if dict1 needs to be updated then
# use dict1 instead of d below
for k,v in dict2.items():
if k in d:
d[max(d)+1] = v # considering the max key in dict1, increment by 1
# else:
# any other condition
Output
# d: {1: 'a', 2: 'b', 3: 'c', 4: 'd', 5: 'e'}

Python3 dictionary merge based on values

I have a dictionary composed of {key: value}.
I select a set of keys from this dictionary.
I'd like to build a new dictionary with {keyA: set of all keys wich have the same value as keyA}.
I already have a solution: Is there a faster way to do it?
It seems very slow to me, and I imagine I'm not the only one in this case!
for key1 in selectedkeys:
if key1 not in seen:
seen.add(key1)
equal[key1] = set([key1])#egual to itself
for key2 in selectedkeys:
if key2 not in seen and dico[key1] == dico[key2]:
equal[key1].add(key2)
seen.update(equal[key1])
Try this
>>> a = {1:1, 2:1, 3:2, 4:2}
>>> ret_val = {}
>>> for k, v in a.iteritems():
... ret_val.setdefault(v, []).append(k)
...
>>> ret_val
{1: [1, 2], 2: [3, 4]}
def convert(d):
result = {}
for k, v in d.items(): # or d.iteritems() if using python 2
if v not in result:
result[v] = set()
result[v].add(k)
return result
or just use collections.defaultdict(set) if you are careful enough not to access any non key later :-)
So you want to create a dictionary that maps key to "the set of all keys which have the same value as key" for each selected key in a given source dictionary.
Thus, if the source dictionary is:
{'a': 1, 'b': 2, 'c': 1, 'd': 2, 'e': 3, 'f': 1, 'g': 3)
and the selected keys are a, b, and e, the result should be:
{'a': {'a', 'c', 'f'}, 'e': {'g', 'e'}, 'b': {'b', 'd'}}
One way to achieve this would be to use a defaultdict to build a value to key table, and then use that to build the required result from the specified keys:
from collections import defaultdict
def value_map(source, keys):
table = defaultdict(set)
for key, value in source.items():
table[value].add(key)
return {key: table[source[key]] for key in keys}
source = {'a': 1, 'b': 2, 'c': 1, 'd': 2, 'e': 3, 'f': 1, 'g': 3)
print(value_map(source, ['a', 'b', 'e']))
Output:
{'a': {'a', 'c', 'f'}, 'e': {'g', 'e'}, 'b': {'b', 'd'}}
Since you select a set of keys from the original dictionary. We can modify #Nilesh solution for your purpose.
a = {1:1, 2:1, 3:2, 4:2}
keys = [1, 3] # lets say this is the list of keys
ret_val = {}
for i in keys:
for k,v in a.items():
if a[i]==v:
ret_val.setdefault(i, []).append(k)
print (ret_val)
{1: [1, 2], 3: [3, 4]}
This was sort of stated in the comments by #Patrick Haugh:
d=your dictionary
s=set(d.values())
d2={i:[] for i in s}
for k in d:
d2[d[k]].append(k)

Categories