Selecting K largest values in a dictionary of dictionary in python - python

I have a dictionary of dictionary as below:
ls = [{'0': {'1': '1','2': '0.5','3': '1'},'1': {'0': '0.2','2': '1','3': '0.8'},}]
I would like to select k-largest values with their keys for each key of dictionary (ls). I have written below commands. It just gives me the k-largest keys without their values.
Python Code:
import heapq
k=2
for dic in ls:
for key in dic:
print(heapq.nlargest(k, dic[key], key=dic[key].get))
Output
['2', '3']
['3', '1']
I need to have value of each selected key.

First of all, I just wanted to check why you have
ls = [{'0': {'1': '1','2': '0.5','3': '1'},'1': {'0': '0.2','2': '1','3': '0.8'},}]
This is a list containing a dict, which doesn't match your description in the question.
Here is a solution that uses dict comprehensions that should give you what you want :)
def get_n_largest_vals(n, d):
x = {key: heapq.nlargest(len, map(int, d[key])) for key in d}
return {key: map(str, x[key]) for key in x}
Here it is being used for your problem:
ls = [{'0': {'1': '1','2': '0.5','3': '1'},'1': {'0': '0.2','2': '1','3': '0.8'},}]
d = ls[0]
get_n_largest_vals(2, d)
>>> {'0': ['3', '2'], '1': ['3', '2']}

How about:
from operator import itemgetter
for d in ls:
for key, d2 in d.items():
print(dict(heapq.nlargest(k, d2.items(), key=itemgetter(1))))
Notice that your values are still strings so they'd be lexically ordered, which is not what you want, because '2' > 12' And the dictionary is not ordered!

Related

Convert string to dictionary with list of values

What is the best way to convert a string to dictionary with value of dictionary as a list
for example
str = "abc=1,abc=2,abc=3,xyz=5,xyz=6"
i need the output as:
d = {"abc":["1","2","3"],"xyz":["5","6"]}
I'm very new to python.
my code:
d = {k: [v] for k, v in map(lambda item: item.split('='), s.split(","))}
Here is the solution with dict.setdefault method.
>>> help({}.setdefault)
Help on built-in function setdefault:
setdefault(key, default=None, /) method of builtins.dict instance
Insert key with a value of default if key is not in the dictionary.
Return the value for key if key is in the dictionary, else default.
>>> your_str = "abc=1,abc=2,abc=3,xyz=5,xyz=6"
>>>
>>> result = {}
>>>
>>> for pair in your_str.split(","):
... name, val = pair.split("=")
... result.setdefault(name, []).append(val)
>>> result
{'abc': ['1', '2', '3'], 'xyz': ['5', '6']}
You could also use defaultdict with default factory as list
>>> from collections import defaultdict
>>>
>>> your_str = "abc=1,abc=2,abc=3,xyz=5,xyz=6"
>>>
>>> result = defaultdict(list)
>>> for pair in str.split(","):
... name, val = pair.split("=")
... result[name].append(val)
...
>>> dict(result)
{'abc': ['1', '2', '3'], 'xyz': ['5', '6']}
The reason the code you have tried already isn't giving you the desired result is the fact that you are overwriting the value assigned to each key as you iterate over the list. What you need to do is append to the value already assigned to the key - except if the key doesn't exist, in which case you need to initialise that key.
This would be one way to go:
s1 = "abc=1,abc=2,abc=3,xyz=5,xyz=6"
list1 = [(each.split('=')) for each in s1.split(',')]
d = {}
for key, val in list1:
if key in d.keys():
d[key].append(val)
else:
d[key] = [val]
print (d)
#result: {'abc': ['1', '2', '3'], 'xyz': ['5', '6']}
You could simplify this and eliminate the if-else by using defaultdict, like so:
from collections import defaultdict
d = defaultdict(lambda: [])
s1 = "abc=1,abc=2,abc=3,xyz=5,xyz=6"
list1 = [(each.split('=')) for each in s1.split(',')]
for key, val in list1:
d[key].append(val)
print (d)
#result: {'abc': ['1', '2', '3'], 'xyz': ['5', '6']}
# initialize a dictionary
d = {}
# split the string (my_str) according to "," in order to get pairs such as 'abc/1' and 'xyz/5' in a list
for elt in my_str.split(",") :
# for each string of the list, split according to '/' to get the pairs ['abc', 1]
# complete the dictionary
if elt.split('/')[0] not in d.keys():
d[elt.split('/')[0]] = [elt.split('/')[1]]
else :
d[elt.split('/')[0]].append(elt.split('/')[1])

Reduce nested dictionary to "top-key-root-element" dictionary

I would like to derive a dictionary from a nested dictionary with the top keys as keys and the root elements as values. This post is similar to this one, but I would like to end up with a dictionary not with a list of lists.
Example: How to get from this
d = {'foo':{'a':{'b':['1','2']}},
'bar':{'a':{'b':{'c':'3'}}}}
to this?
{'foo': ['1', '2'], 'bar': '3'}
d = {'foo':{'a':{'b':['1','2']}},
'bar':{'c':{'d':'3'}}}
def get_last_value(d):
if isinstance(d, dict):
for k, v in d.items():
return get_last_value(v)
return d
result = {k:get_last_value(v) for k, v in d.items()}
print(result)
result:
{'foo': ['1', '2'], 'bar': '3'}
d = {'foo':{'a':{'b':['1','2']}},
'bar':{'c':{'d':'3'}}}
for key, value, in d.items():
print(key, value.values())

Python Dictionary using Lists as Values, find other Keys with same values

Say I have the following dictionary.
>> sample_dict = {"1": ['a','b','c'], "2": ['d','e','f'], "3": ['g','h','a']}
I would like to find a way that would look at the values of each of the keys and return whether or not the value lists have the a duplicate variable inside.
For example it would output:
>> [["1","3"] , ['a']]
I've looked at a few of the posts here and tried to use and/or change them to accomplish this, however none of what I have found has worked as intended. They would work if it was as follows:
>> sample_dict = {"1": ['a','b','c'], "2": ['d','e','f'], "3": ['a','b','c']}
but not if only a single value within the list was the same.
You could use another dictionary to map the values to the lists of corresponding keys. Then just select the values that map to more than one key, e.g.:
from collections import defaultdict
sample_dict = {'1': ['a','b','c'], '2': ['d','e','f'], '3': ['g','h','a']}
d = defaultdict(list) # automatically initialize every value to a list()
for k, v in sample_dict.items():
for x in v:
d[x].append(k)
for k, v in d.items():
if len(v) > 1:
print([v, k])
Output:
[['1', '3'], 'a']
If the list elements are hashable, you can use .setdefault to build an inverse mapping like so:
>>> sample_dict = {"1": ['a','b','c'], "2": ['d','e','f'], "3": ['g','h','a']}
>>> aux = {}
>>> for k, v in sample_dict.items():
... for i in v:
... aux.setdefault(i, []).append(k)
...
>>> [[v, k] for k, v in aux.items() if len(v) > 1]
[[['1', '3'], 'a']]
Dictionaries map from keys to values, not from values to keys. But you can write a function for one-off calculations. This will incur O(n) time complexity and is not recommended for larger dictionaries:
def find_keys(d, val):
return [k for k, v in d.items() if val in v]
res = find_keys(sample_dict, 'a') # ['1', '3']
If you do this often, I recommend you "invert" your dictionary via collections.defaultdict:
from collections import defaultdict
dd = defaultdict(list)
for k, v in sample_dict.items():
for w in v:
dd[w].append(k)
print(dd)
defaultdict(<class 'list'>, {'a': ['1', '3'], 'b': ['1'], 'c': ['1'], 'd': ['2'],
'e': ['2'], 'f': ['2'], 'g': ['3'], 'h': ['3']})
This costs O(n) for the inversion, as well as additional memory, but now allows you to access the keys associated with an input value in O(1) time, e.g. dd['a'] will return ['1', '3'].
You can use defaultdict from collections module to do this
for example,
from collections import defaultdict
sample_dict = {"1": ['a','b','c'], "2": ['d','e','f'], "3": ['g','h','a']}
d = defaultdict(list)
for keys, vals in sample_dict.items():
for v in vals:
d[v].append(keys)
print(d)
d will return a dict, where the keys will be the values that are repeated and values will be the list in which they were repeated in
The output of above code is defaultdict(list,{'a': ['1', '3'],'b': ['1'],'c': ['1'],'d': ['2'],'e': ['2'],'f': ['2'],'g': ['3'],'h': ['3']})
​
Although it IS possible to get form in which you desired the output to be in, but it is not generally recommended because we are trying to get what character get repeated in which list, that feels like a job of a dictionary

How to find the similarities for set and print the value

I hope to make a dictionary and a list into set then if a.keys() == b then I will print the a.values().
Example:
c = [{'1': '0'}, {'0': '5'},{'2': '0'}]
d = {1,2}
I hope to make these two into the set. Then find all the similarities and print the values without changing the sequence.
Example, I want to print this.
{'1': '0'}
{'2': '0'}
Is it possible to use set?
Below is my code:
a = set(c.keys()) & set(d)
print(a)
for x in a:
y,z = c[x]
Since your example set contains integers while the keys in your example dicts are strings, you should convert the integers in the set to strings first. After that you can simply loop through each dict in the list and if the keys of the dict intersects with the set, then print the dict since it's a match:
d = set(map(str, d))
for i in c:
if i.keys() & d:
print(i)
This outputs:
{'1': '0'}
{'2': '0'}
First of all, you specified your input values the wrong way. The dictionary c should be defined as a dictionary with keys and values and not as a list of dictionaries with one item each - as you did. The keys should be specified as integer and not as string. Otherwise you need to cast them from string to int later on. The second item d is specified the wrong way, too. This should be a list of integers and not a dictionary.
Here's the code that specifies the input values correctly and gives you the desired output:
c = {1: '0', 0: '5', 2: '0'}
d = [1,2]
distinct_keys = c.keys() & set(d)
# {1, 2}
distinct_values = {key: value for key, value in c.items() if key in distinct_keys}
# {1: '0', 2: '0'}
distinct_values
This gives {1: '0', 2: '0'} as output.

is it possible to reverse a dictionary in python using dictionary comprehension

I want to reverse dictionary key, value pairs using a dictionary comprehension, but if the new dictionary has more than one value for a key then it is getting replaced with the last value.
Is it possible to append to the values in the new dictionary if a key is repeated, using a comprehension?
Input:
test_di = {'a':'1', 'b':'2', 'c':'3', 'd':'2'}
Code:
{v:k for k,v in test_di.items()}
Output of this code:
{'1': 'a', '3': 'c', '2': 'd'}
Desired output:
{'1': ['a'], '3': ['c'], '2': ['b','d']}
It's not possible to do it in a reasonable way (i.e. O(N) time) with a dictionary comprehension. The comprehension simply can't handle duplicated values.
However, it's quite easy with a regular loop:
d = {}
for key, value in old_d.items():
d.setdefault(value, []).append(key)
A defaultdict would be the most efficient approach:
from collections import defaultdict
test_di = {'a':'1', 'b':'2', 'c':'3', 'd':'2'}
d = defaultdict(list)
for v,k in test_di.items():
d[k].append(v)
print(d)
Your question is confusing, but it sounds like you want to store multiple values at a single key in a dictionary.
This is not possible, you may want to look at storing a dictionary of lists.
You can use an OrderedDict and reverse the keys. A normal dict does not keep track of the order of the keys.
from collections import OrderedDict
dict1 = OrderedDict([('Name', 'Jon'), ('Race', 'Latino'), ('Job', 'Nurse')])
reversed_dict1 = OrderedDict([(key, dict1.get(key)) for key in reversed(dict1)])
Yes, it is possible (but it’s not the most efficient solution):
d = {'a':'1', 'b':'2', 'c':'3', 'd':'2'}
{v1: [k1 for k1, v2 in d.items() if v1 == v2] for v1 in d.values()}
# {'1': ['a'], '2': ['b', 'd'], '3': ['c']}

Categories