How to change the positions of a dictionary? [duplicate] - python

This question already has answers here:
Reverse / invert a dictionary mapping
(32 answers)
Closed 10 months ago.
I have a dictionary as follows:
d = {'a': ['b'], 'c': ['d']}
I want to change the positions of the dictionary so that it looks like the following:
d_new = {'b': 'a', 'd': 'c'}
I have tried the following, but due to the second term being a list in my original dictionary (d), I am unable to complete this.
d = {'a': ['b'], 'c': ['d']}
for k in list(d.keys()):
d[d.pop(k)] = k
print(d)

You can use iterable unpacking in a dict comprehension like so:
{v: k for k, (v,) in d.items()}
>>> d = {'a': ['b'], 'c': ['d']}
>>> {v: k for k, (v,) in d.items()}
{'b': 'a', 'd': 'c'}
This assumes all values are a list of one element and you only want the first element in the lists.
Otherwise you can use this more appropriate code:
{v[0] if isinstance(v, list) else v: k for k, v in d.items()}

A variation on a theme using list unpacking:
d = {'a': ['b'], 'c': ['d']}
d = {v: k for k, [v] in d.items()}
print(d)
In case the values (lists) happen to contain more than one element and you're only interested in the first element then:
d = {v:k for k, [v,*_] in d.items()}
Of course, this could also be used even if there's only one element per list

Related

How to merge keys of dictionary which have the same value?

I need to combine two dictionaries by their value, resulting in a new key which is the list of keys with the shared value. All I can find online is how to add two values with the same key or how to simply combine two dictionaries, so perhaps I am just searching in the wrong places.
To give an idea:
dic1 = {'A': 'B', 'C': 'D'}
dic2 = {'D': 'B', 'E': 'F'}
Should result in:
dic3 = {['A', 'D']: 'B', 'C': 'D', 'E': 'F'}
I am not sure why you would need such a data structure, you can probably find a better solution to your problem. However, just for the sake of answering your question, here is a possible solution:
dic1 = {'A':'B', 'C':'D'}
dic2 = {'D':'B', 'E':'F'}
key_list = list(dic2.keys())
val_list = list(dic2.values())
r = {}
for k,v in dic1.items():
if v in val_list:
i = val_list.index(v) #get index at value
k2 = key_list[i] #use index to retrive the key at value
r[(k, k2)] = v #make the dict entry
else:
r[k] = v
val_list = list(r.values()) #get all the values already processed
for k,v in dic2.items():
if v not in val_list: #if missing value
r[k] = v #add new entry
print(r)
output:
{('A', 'D'): 'B', 'C': 'D', 'E': 'F'}
You can't assign a list as a key in a python dictionary since the key must be hashable and a list is not an ashable object, so I have used a tuple instead.
I would use a defaultdict of lists and build a reversed dict and in the end reverse it while converting the lists to tuples (because lists are not hashable and can't be used as dict keys):
from collections import defaultdict
dic1 = {'A':'B', 'C':'D'}
dic2 = {'D':'B', 'E':'F'}
temp = defaultdict(list)
for d in (dic1, dic2):
for key, value in d.items():
temp[value].append(key)
print(temp)
res = {}
for key, value in temp.items():
if len(value) == 1:
res[value[0]] = key
else:
res[tuple(value)] = key
print(res)
The printout from this (showing the middle step of temp) is:
defaultdict(<class 'list'>, {'B': ['A', 'D'], 'D': ['C'], 'F': ['E']})
{('A', 'D'): 'B', 'C': 'D', 'E': 'F'}
If you are willing to compromise from 1-element tuples as keys, the second part will become much simpler:
res = {tuple(value): key for key, value in temp.items()}

Printing unique keys from nested dictionary in python

I have a dictionary dict_matches with 2 inner dictionaries.
The structure of dict_match is as follows:
dict_match = {Query_ID:{Function_ID:{DB_ID:[func_ID]}}}
Within the top level of keys Query_ID, I loop through these and compare these against keys in a completely separate dict query_count_dict to determine the overlap of keys.
Within this loop I also navigate to the base dict in dict_matches in order to see what keys DB_ID the master key has 'matched' with. My problem is that this lower-level of keys DB_ID that correspond to the very top-level key Query_ID can be duplicated (and I only want to see the unique keys). I tried using the set() method but this actually split the string keys into their character components and printed the unique characters for each lower-level key. Any help appreciated!
See code below
for k,v in dict_match.items():
if k in query_count_dict.keys():
print(k)
detection_query.append(k)
print(len(dict_match[k])/int(query_count_dict[k]))
if type(v) is dict:
recursive_items(v)
where recursive_items is a function to navigate to the base dict:
def recursive_items(dictionary):
for k, v in dictionary.items():
if type(v) is dict:
recursive_items(v)
else:
print(set(k))
You can print all the unique keys by passing a list of keys in your recursive function, to store them as you navigate to the base. Then cast it to set to remove the duplicates.
def get_keys(dictionary, keys=[]):
for k, v in dictionary.items():
keys.append(k)
if isinstance(v, dict):
get_keys(v, keys)
return set(keys)
dict_match = {'A': {'A': {'B': [0], 'H': [0]}, 'D': {'C': [0], 'A': [0]}},
'B': {'C': {'A': [0]}, 'G': {'A': [0]}},
'C': {'A': {'E': [0]}, 'B': {'F': [0], 'A': [0]}, 'C': {'B': [0]}}}
print(get_keys(dict_match))
And it will output only the unique keys:
{'G', 'B', 'E', 'F', 'C', 'H', 'A', 'D'}

Dictionary value replace

Imagine I have a dictionary like this:
d = {'1':['a'], '2':['b', 'c', 'd'], '3':['e', 'f'], '4':['g']}
Each key of the dictionary represents a unique person of a certain class.
Each key must have only one value.
Key's with one value represent the correct reassignment.
Key's with more than one value represent the possibilities. One of those values is the most correct for that key.
I have a processed list with the most correct value.
LIST = ['c', 'e']
I must now iterate values of LIST through values of dictionary when len(values) > 1 and replace them to look like this:
d = {'1':['a'], '2':['c'], '3':['e'], '4':['g']}
Initialise your correct values inside a set.
correct = {'c', 'e'}
# correct = set(LIST)
Now, assuming list values with more than one element can have only a single correct element, you can build a dictionary using a conditional comprehension:
d2 = {k : list(correct.intersection(v)) if len(v) > 1 else v for k, v in d.items()}
print(d2)
# {'1': ['a'], '2': ['c'], '3': ['e'], '4': ['g']}
If there can be more than one possible correct value, you can take just the first one.
d2 = {}
for k, v in d.items():
if len(v) > 1:
c = list(correct.intersection(v))
v = c[:1]
d2[k] = v
print(d2)
# {'1': ['a'], '2': ['c'], '3': ['e'], '4': ['g']}
If you meant to mutate d in-place (because making a full copy can be expensive), then the above solution simplifies to
for k, v in d.items():
if len(v) > 1:
c = list(correct.intersection(v))
d[k] = c[:1]
print(d)
# {'1': ['a'], '2': ['c'], '3': ['e'], '4': ['g']}
Another approach in one statement using dict comprehension:
d = {'1':['a'], '2':['b', 'c', 'd'], '3':['e', 'f'], '4':['g']}
a = ['c', 'e']
output = {k: v if not any(j in set(a) for j in v) else list(set(v) & set(a)) if v and isinstance(v, (list, tuple)) else [] for k, v in d.items()}
# More readeable like this:
# {
# k: v if not any(j in set(a) for j in v) else list(set(v) & set(a))
# if v and isinstance(v, (list, tuple))
# else [] for k, v in d.items()
# }
print(output)
Output:
{'1': ['a'], '2': ['c'], '3': ['e'], '4': ['g']}

specific value based filtering on a large dictionary in Python

I am having a very large dictionary. Here is a small sampling of my dictionary:
dictionary = {'1': {'a':'aa','b':'bb','c':'cc','d':'dd'},
'2': {'a':'aa','b':'bb','c':'cc','d':'dd'},
'3': {'a':'aa','b':'bb','c':'cc','d':'dd'} }
I just want to filter out the a & c.
Desired output:
dictionary = { '1': {'a':'aa','c':'cc'},
'2': {'a':'aa','c':'cc'},
'3': {'a':'aa','c':'cc'} }
Dictionary comprehensions to the rescue:
{k: {'a': v['a'], 'c': v['c']} for k, v in dictionary.iteritems()}
This assumes that all dictionaries in have those keys set and that you are using Python 2.7.
A more generic version:
def filtered_dicts(d, keys):
return {k: {vk: v[vk] for vk in v.viewkeys() & keys} for k, v in d.iteritems()}
dictionary = filtered_dicts(dictionary, {'a', 'c'})
This will work even if the keys are not present in all values of dictionary.
Any iterable will do for keys here; I used a set literal here but a list or tuple or even a string would work too.
A Python 3 version of the latter:
def filtered_dicts(d, keys):
return {k: {vk: v[vk] for vk in v.keys() & keys} for k, v in d.items()}
Quick demo using Python 3:
>>> dictionary = {'1': {'a':'aa','b':'bb','c':'cc','d':'dd'}, '2': {'a':'aa','b':'bb','c':'cc','d':'dd'}, '3':{'a':'aa','b':'bb','c':'cc','d':'dd'}}
>>> def filtered_dicts(d, keys):
... return {k: {vk: v[vk] for vk in v.keys() & keys} for k, v in d.items()}
...
>>> filtered_dicts(dictionary, {'a', 'c'})
{'3': {'c': 'cc', 'a': 'aa'}, '2': {'c': 'cc', 'a': 'aa'}, '1': {'c': 'cc', 'a': 'aa'}}

Python miminum value in dictionary of lists

Sorry about the question repost...I should have just edited this question in the first place. Flagged the new one for the mods. Sorry for the trouble
Had to re-write the question due to changed requirements.
I have a dictionary such as the following:
d = {'a': [4, 2], 'b': [3, 4], 'c': [4, 3], 'd': [4, 3], 'e': [4], 'f': [4], 'g': [4]}
I want to get the keys that are associated with the smallest length in the dictionary d, as well as those that have the maximum value.
In this case, the keys with the smallest length (smallest length of lists in this dictionary) should return
'e, 'f', 'g'
And those with the greatest value(the sum of the integers in each list) should return
'b' 'c'
I have tried
min_value = min(dict.itervalues())
min_keys = [k for k in d if dict[k] == min_value]
But that does not give me the result I want.
Any ideas?
Thanks!
Your problem is that your lists contain strings ('2'), and not integers (2). Leave out the quotes, or use the following:
min_value = min(min(map(int, v) for v in dct.values()))
min_keys = [k for k,v in d.items() if min_value in map(int, v)]
Similarily, to calculate the keys with the max length:
max_length = max(map(len, dct.values()))
maxlen_keys = [k for k,v in d.items() if max_length == len(v)]
Also, it's a bad idea to use dict as a variable name, as doing so overshadows the built-in dict.
You can use min() with a key= argument, and specify a key function that compares the way you want.
d = {'a': ['1'], 'b': ['1', '2'], 'c': ['2'], 'd':['1']}
min_value = min(d.values())
min_list = [key for key, value in d.items() if value == min_value]
max_len = len(max(d.values(), key=len))
long_list = [key for key, value in d.items() if len(value) == max_len]
print(min_list)
print(long_list)
Notes:
0) Don't use dict as a variable name; that's the name of the class for dictionary, and if you use it as a variable name you "shadow" it. I just used d for the name here.
1) min_value was easy; no need to use a key= function.
2) max_len uses a key= function, len(), to find the longest value.
How about using sorting and lambdas?
#!/usr/bin/env python
d = {'a': ['1'], 'b': ['1', '2'], 'c': ['8', '1'], 'd':['1'], 'e':['1', '2', '3'], 'f': [4, 1]}
sorted_by_sum_d = sorted(d, key=lambda key: sum(list(int(item) for item in d[key])))
sorted_by_length_d = sorted(d, key=lambda key: len(d[key]))
print "Sorted by sum of the items in the list : %s" % sorted_by_sum_d
print "Sorted by length of the items in the list : %s" % sorted_by_length_d
This would output:
Sorted by sum of the items in the list : ['a', 'd', 'b', 'f', 'e', 'c']
Sorted by length of the items in the list : ['a', 'd', 'c', 'b', 'f', 'e']
Be aware I changed the initial 'd' dictionary (just to make sure it was working)
Then, if you want the item with the biggest sum, you get the last element of the sorted_by_sum_d list.
(I'm not too sure this is what you want, though)
Edit:
If you can ensure that the lists are always going to be lists of integers (or numeric types, for that matter, such as long, float...), there's not need to cast strings to integers. The calculation of the sorted_by_sum_d variable can be done simply using:
d = {'a': [1], 'b': [1, 2], 'c': [8, 1], 'd':[1], 'e':[1, 2, 3], 'f': [4, 1]}
sorted_by_sum_d = sorted(d, key=lambda key: sum(d[key]))
I've found such a simple solution:
min_len = len(min(d.values(), key=(lambda value: len(value)))) # 1
min_keys = [key for i, key in enumerate(d) if len(d[key]) == min_len] # ['e', 'f', 'g']

Categories

Resources