Python3 dictionary merge based on values - python

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)

Related

How can I add n times a value in a dictionary? [duplicate]

Can I use list comprehension syntax to create a dictionary?
For example, by iterating over pairs of keys and values:
d = {... for k, v in zip(keys, values)}
Use a dict comprehension (Python 2.7 and later):
{key: value for (key, value) in iterable}
Alternatively for simpler cases or earlier version of Python, use the dict constructor, e.g.:
pairs = [('a', 1), ('b', 2)]
dict(pairs) #=> {'a': 1, 'b': 2}
dict([(k, v+1) for k, v in pairs]) #=> {'a': 2, 'b': 3}
Given separate arrays of keys and values, use the dict constructor with zip:
keys = ['a', 'b']
values = [1, 2]
dict(zip(keys, values)) #=> {'a': 1, 'b': 2}
2) "zip'ped" from two separate iterables of keys/vals
dict(zip(list_of_keys, list_of_values))
In Python 3 and Python 2.7+, dictionary comprehensions look like the below:
d = {k:v for k, v in iterable}
For Python 2.6 or earlier, see fortran's answer.
In fact, you don't even need to iterate over the iterable if it already comprehends some kind of mapping, the dict constructor doing it graciously for you:
>>> ts = [(1, 2), (3, 4), (5, 6)]
>>> dict(ts)
{1: 2, 3: 4, 5: 6}
>>> gen = ((i, i+1) for i in range(1, 6, 2))
>>> gen
<generator object <genexpr> at 0xb7201c5c>
>>> dict(gen)
{1: 2, 3: 4, 5: 6}
Create a dictionary with list comprehension in Python
I like the Python list comprehension syntax.
Can it be used to create dictionaries too? For example, by iterating
over pairs of keys and values:
mydict = {(k,v) for (k,v) in blah blah blah}
You're looking for the phrase "dict comprehension" - it's actually:
mydict = {k: v for k, v in iterable}
Assuming blah blah blah is an iterable of two-tuples - you're so close. Let's create some "blahs" like that:
blahs = [('blah0', 'blah'), ('blah1', 'blah'), ('blah2', 'blah'), ('blah3', 'blah')]
Dict comprehension syntax:
Now the syntax here is the mapping part. What makes this a dict comprehension instead of a set comprehension (which is what your pseudo-code approximates) is the colon, : like below:
mydict = {k: v for k, v in blahs}
And we see that it worked, and should retain insertion order as-of Python 3.7:
>>> mydict
{'blah0': 'blah', 'blah1': 'blah', 'blah2': 'blah', 'blah3': 'blah'}
In Python 2 and up to 3.6, order was not guaranteed:
>>> mydict
{'blah0': 'blah', 'blah1': 'blah', 'blah3': 'blah', 'blah2': 'blah'}
Adding a Filter:
All comprehensions feature a mapping component and a filtering component that you can provide with arbitrary expressions.
So you can add a filter part to the end:
>>> mydict = {k: v for k, v in blahs if not int(k[-1]) % 2}
>>> mydict
{'blah0': 'blah', 'blah2': 'blah'}
Here we are just testing for if the last character is divisible by 2 to filter out data before mapping the keys and values.
In Python 2.7, it goes like:
>>> list1, list2 = ['a', 'b', 'c'], [1,2,3]
>>> dict( zip( list1, list2))
{'a': 1, 'c': 3, 'b': 2}
Zip them!
Python version >= 2.7, do the below:
d = {i: True for i in [1,2,3]}
Python version < 2.7(RIP, 3 July 2010 - 31 December 2019), do the below:
d = dict((i,True) for i in [1,2,3])
To add onto #fortran's answer, if you want to iterate over a list of keys key_list as well as a list of values value_list:
d = dict((key, value) for (key, value) in zip(key_list, value_list))
or
d = {(key, value) for (key, value) in zip(key_list, value_list)}
Just to throw in another example. Imagine you have the following list:
nums = [4,2,2,1,3]
and you want to turn it into a dict where the key is the index and value is the element in the list. You can do so with the following line of code:
{index:nums[index] for index in range(0,len(nums))}
Here is another example of dictionary creation using dict comprehension:
What i am tring to do here is to create a alphabet dictionary where each pair; is the english letter and its corresponding position in english alphabet
>>> import string
>>> dict1 = {value: (int(key) + 1) for key, value in
enumerate(list(string.ascii_lowercase))}
>>> dict1
{'a': 1, 'c': 3, 'b': 2, 'e': 5, 'd': 4, 'g': 7, 'f': 6, 'i': 9, 'h': 8,
'k': 11, 'j': 10, 'm': 13, 'l': 12, 'o': 15, 'n': 14, 'q': 17, 'p': 16, 's':
19, 'r': 18, 'u': 21, 't': 20, 'w': 23, 'v': 22, 'y': 25, 'x': 24, 'z': 26}
>>>
Notice the use of enumerate here to get a list of alphabets and their indexes in the list and swapping the alphabets and indices to generate the key value pair for dictionary
Hope it gives a good idea of dictionary comp to you and encourages you to use it more often to make your code compact
This code will create dictionary using list comprehension for multiple lists with different values that can be used for pd.DataFrame()
#Multiple lists
model=['A', 'B', 'C', 'D']
launched=[1983,1984,1984,1984]
discontinued=[1986, 1985, 1984, 1986]
#Dictionary with list comprehension
keys=['model','launched','discontinued']
vals=[model, launched,discontinued]
data = {key:vals[n] for n, key in enumerate(keys)}
#Convert dict to dataframe
df=pd.DataFrame(data)
display(df)
enumerate will pass n to vals to match each key with its list
Try this,
def get_dic_from_two_lists(keys, values):
return { keys[i] : values[i] for i in range(len(keys)) }
Assume we have two lists country and capital
country = ['India', 'Pakistan', 'China']
capital = ['New Delhi', 'Islamabad', 'Beijing']
Then create dictionary from the two lists:
print get_dic_from_two_lists(country, capital)
The output is like this,
{'Pakistan': 'Islamabad', 'China': 'Beijing', 'India': 'New Delhi'}
Adding to #Ekhtiar answer, if you want to make look up dict from list, you can use this:
names = ['a', 'b', 'd', 'f', 'c']
names_to_id = {v:k for k, v in enumerate(names)}
# {'a': 0, 'b': 1, 'c': 2, 'd': 3, 'f': 4}
Or in rare case that you want to filter duplicate, use set first (best in list of number):
names = ['a', 'b', 'd', 'f', 'd', 'c']
sorted_list = list(set(names))
sorted_list.sort()
names_to_id = {v:k for k, v in enumerate(sorted_list)}
# {'a': 0, 'b': 1, 'c': 2, 'd': 3, 'f': 4}
names = [1,2,5,5,6,2,1]
names_to_id = {v:k for k, v in enumerate(set(names))}
# {1: 0, 2: 1, 5: 2, 6: 3}
>>> {k: v**3 for (k, v) in zip(string.ascii_lowercase, range(26))}
Python supports dict comprehensions, which allow you to express the creation of dictionaries at runtime using a similarly concise syntax.
A dictionary comprehension takes the form {key: value for (key, value) in iterable}. This syntax was introduced in Python 3 and backported as far as Python 2.7, so you should be able to use it regardless of which version of Python you have installed.
A canonical example is taking two lists and creating a dictionary where the item at each position in the first list becomes a key and the item at the corresponding position in the second list becomes the value.
The zip function used inside this comprehension returns an iterator of tuples, where each element in the tuple is taken from the same position in each of the input iterables. In the example above, the returned iterator contains the tuples (“a”, 1), (“b”, 2), etc.
Output:
{'i': 512, 'e': 64, 'o': 2744, 'h': 343, 'l': 1331, 's': 5832, 'b': 1, 'w': 10648, 'c': 8, 'x': 12167, 'y': 13824, 't': 6859, 'p': 3375, 'd': 27, 'j': 729, 'a': 0, 'z': 15625, 'f': 125, 'q': 4096, 'u': 8000, 'n': 2197, 'm': 1728, 'r': 4913, 'k': 1000, 'g': 216, 'v': 9261}
Yes, it's possible. In python, Comprehension can be used in List, Set, Dictionary, etc.
You can write it this way
mydict = {k:v for (k,v) in blah}
Another detailed example of Dictionary Comprehension with the Conditional Statement and Loop:
parents = [father, mother]
parents = {parent:1 - P["mutation"] if parent in two_genes else 0.5 if parent in one_gene else P["mutation"] for parent in parents}
You can create a new dict for each pair and merge it with the previous dict:
reduce(lambda p, q: {**p, **{q[0]: q[1]}}, bla bla bla, {})
Obviously this approaches requires reduce from functools.
Assuming blah blah blah is a two-tuples list:
Let's see two methods:
# method 1
>>> lst = [('a', 2), ('b', 4), ('c', 6)]
>>> dict(lst)
{'a': 2, 'b': 4, 'c': 6}
# method 2
>>> lst = [('a', 2), ('b', 4), ('c', 6)]
>>> d = {k:v for k, v in lst}
>>> d
{'a': 2, 'b': 4, 'c': 6}
this approach uses iteration over the given date using a for loop.
Syntax: {key: value for (key, value) in data}
Eg:
# create a list comprehension with country and code:
Country_code = [('China', 86), ('USA', 1),
('Ghana', 233), ('Uk', 44)]
# use iterable method to show results
{key: value for (key, value) in Country_code}

how to check every dictionary is perfect in list , python

I have a data set as below
tmp_dict = {
'a': ?,
'b': ?,
'c': ?,
}
and I have a data is a list of dictionaries like
tmp_list = [tmp_dict1, tmp_dict2, tmp_dict3....]
and I found some of dictionaries are not perfectly have keys about 'a','b','c'.
How do I check and fill the key is not existing
You could try something like this:
# List of keys to look for in each dictionary
dict_keys = ['a','b','c']
# Generate the dictionaries for demonstration purposes only
tmp_dict1 = {'a':[1,2,3], 'b':[4,5,6]}
tmp_dict2 = {'a':[7,8,9], 'b':[10,11,12], 'c':[13,14,15]}
tmp_dict3 = {'a':[16,17,18], 'c':[19,20,21]}
# Add the dictionaries to a list as per OP instructions
tmp_list = [tmp_dict1, tmp_dict2, tmp_dict3]
#--------------------------------------------------------
# Check for missing keys in each dict.
# Print the dict name and keys missing.
# -------------------------------------------------------
for i, dct in enumerate(tmp_list, start=1):
for k in dict_keys:
if dct.get(k) == None:
print(f"tmp_dict{i} is missing key:", k)
OUTPUT:
tmp_dict1 is missing key: c
tmp_dict3 is missing key: b
I think you want this.
tmp_dict = {'a':1, 'b': 2, 'c':3}
default_keys = tmp_dict.keys()
tmp_list = [{'a': 1}, {'b': 2,}, {'c': 3}]
for t in tmp_list:
current_dict = t.keys()
if default_keys - current_dict:
t.update({diff: None for diff in list(default_keys-current_dict)})
print(tmp_list)
Output:
[{'a': 1, 'c': None, 'b': None}, {'b': 2, 'a': None, 'c': None}, {'c': 3, 'a': None, 'b': None}]
You can compare the keys in the dictionary with a set containing all the expected keys.
for d in tmp_list:
if set(d) != {'a', 'b', 'c'}:
print(d)

Group list of dictionaries by value [duplicate]

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

Weave two dictionaries into one

I have two dictionaries:
dict1 = {'a': 1,
'b': 2,
'c': 3,
'd': 4,
'x': 5}
and
dict2 = {'a': 'start',
'b': 'start',
'c': 'end',
'd': 'end'}
I am trying to create a new dictionary that maps the values start and end as keys to a dictionary that would contain the info of dict1, while keeping those that are not present in dict2 as keys, e.g.:
dict3 = {'start': {'a': 1, 'b': 2},
'end': {'c': 3, 'd': 4},
'x': {'x': 5}
}
Use dict.setdefault() to create the nested dictionaries in dict3 if not yet there, and dict.get() to determine the key in the top-level output dictionary:
dict3 = {}
for k, v in dict1.items():
nested = dict3.setdefault(dict2.get(k, k), {})
nested[k] = v
So dict2.get(k, k) will produce the value from dict2 for a given key from dict1, using the key itself as a default. So for the 'x' key, that'll produce 'x' as there is no mapping in dict2 for that key.
Demo:
>>> dict3 = {}
>>> for k, v in dict1.items():
... nested = dict3.setdefault(dict2.get(k, k), {})
... nested[k] = v
...
>>> dict3
{'start': {'a': 1, 'b': 2}, 'end': {'c': 3, 'd': 4}, 'x': {'x': 5}}
I actually figured it out while abstracting the example and typing up my question here (should have maybe done this earlier...). Anyways: Yay!
So here is my solution, in case it may help someone. If someone knows a swifter or more elegant way to do it, I would be glad to learn!
dict3 = dict()
for k, v in dict1.items():
# if the key of dict1 exists also in dict2
if k in dict2.keys():
# get its value (the keys-to-be for the new dict3)
new_key = dict2[k]
# if the new key is already in the new dict
if new_key in dict3.keys():
# appends new dict entry to dict3
dict3[new_key].update({k: v})
# otherwise create a new entry
else:
dict3[new_key] = {k: v}
# if there is no corresponding mapping present
else:
# treat the original key as the new key and add to dict3
no_map = k
dict3[no_map] = {k: v}

How to reverse a dictionary that has repeated values

I have a dictionary with almost 100,000 (key, value) pairs and the majority of the keys map to the same values. For example:
mydict = {'a': 1, 'c': 2, 'b': 1, 'e': 2, 'd': 3, 'h': 1, 'j': 3}
What I want to do, is to reverse the dictionary so that each value in mydict is going to be a key at the reverse_dict and is going to map to a list of all the mydict.keys() that used to map to that value in mydict. So based on the example above I would get:
reversed_dict = {1: ['a', 'b', 'h'], 2: ['c', 'e'] , 3: ['d', 'j']}
I came up with a solution that is very expensive and I want to hear any ideas for doing this more efficiently than this:
reversed_dict = {}
for value in mydict.values():
reversed_dict[value] = []
for key in mydict.keys():
if mydict[key] == value:
if key not in reversed_dict[value]:
reversed_dict[value].append(key)
Using collections.defaultdict:
from collections import defaultdict
reversed_dict = defaultdict(list)
for key, value in mydict.items():
reversed_dict[value].append(key)
reversed_dict = {}
for key, value in mydict.items():
reversed_dict.setdefault(value, [])
reversed_dict[value].append(key)
for k,v in dict.iteritems():
try:
reversed_dict[v].append(k)
except KeyError:
reversed_dict[v]=[k]
I think you're wasting a few cycles by replacing a key with the same key again and again...
reversed_dict = {}
for value in mydict.values():
if value not in reversed_dict.keys(): #checking to be sure it hasn't been done.
reversed_dict[value] = []
for key in mydict.keys():
if mydict[key] == value:
if key not in reversed_dict[value]: reversed_dict[value].append(key)
Using itertools.groupby:
from operator import itemgetter
from itertools import groupby
snd = itemgetter(1)
def sort_and_group(itr, f):
return groupby(sorted(itr, key=f), f)
mydict = {'a': 1, 'c': 2, 'b': 1, 'e': 2, 'd': 3, 'h': 1, 'j': 3}
reversed_dict = {number: [char for char,_ in v]
for number, v in sort_and_group(mydict.items(), snd)}
reversed_dict = collections.defaultdict(list)
for key, value in dict_.iteritems():
reversed_dict[value].append(key)
def reverse_dict(mydict):
v={}
for x,y in mydict.items():
if y not in v:
v[y]=[x]
else:
v[y].append(x)
return v
print(reverse_dict(mydict))

Categories