I have a dictionary, i need to sort it on the descending order of the MI Value.And print the contents in dict one by one in descending order along with 'hi'
My coding:
d = dict()
for item in a:
specificy = c[item]
MI1= specificx/float(specificy)
MI2= MI1*specificx
M13= specificx*specificy
MI = MI1* math.log(MI1/float(MI2))
d[x + ' ' + item] = MI
print d
for k,v in d:
print k + v + 'hi'
This should do:
import operator
for k in sorted(d.items(), key=operator.itemgetter(1), reverse=True):
print(k + d[k] + 'hi')
It works by getting the items of the dictionary, sorting them by the values, reversed, then printing that.
See also: https://stackoverflow.com/a/613218/565635
To sort using key change index of x to 0
for k,v in sorted(d.items(), key=lambda x: x[0], reverse=False):
print k + v + 'hi'
To sort using value change index of x to 1
for k,v in sorted(d.items(), key=lambda x: x[1], reverse=False):
print k + v + 'hi'
To sort a dictionary on the item value you can use
sorted(d, key=d.__getitem__)
In your case the code becomes
for k in sorted(d, key=d.__getitem__, reverse=True):
print(k + d[k] + "hi")
Explanation
When in Python you write
d[k]
what is evaluated is
d.__getitem__(k)
so d.__getitem__ when d is a dictionary is a function that given a key returns the value associated to that key in the dictionary.
sorted instead is a predefined function that returns a sorted version of a sequence and accepts an optional parameter (named somewhat unfortunately key, but note that key has no relation to dictionaries here). This parameter can be used to determine on what the ordering comparison should be done; sorted also supports another optional parameter reversed where you can determine if ascendant or descendant sorting is required.
Finally when a dictionary is used as a sequence (for example passing it to sorted or iterating over it in a for) what you obtain are the keys of the dictionary.
This for example implies that sorted(d, key=d.__getitem__) returns the keys of the dictionary sorted according the value.
Related
I am trying to find the fastest way to get the dictionary key with the most items. The two methods I have tried so far are:
def get_key_with_most_items(d):
maxcount = max(len(v) for v in d.values())
return [k for k, v in d.items() if len(v) == maxcount][0]
and
def sort_by_values_len(dict):
dict_len = {key: len(value) for key, value in dict.items()}
import operator
sorted_key_list = sorted(dict_len.items(), key=operator.itemgetter(1), reverse=True)
sorted_dict = [{item[0]: dict[item [0]]} for item in sorted_key_list]
return sorted_dict
The first method return the key with the biggest number of items, while the second returns the whole dictionary as a list. In my case I only need the key, just to be clear. After comparing these methods in this manner:
start_time = time.time()
for i in range(1000000):
get_key_with_most_items(my_dict) # sort_by_values_len(my_dict)
print("Time", (time.time() - start_time))
I have come to the conclusion that the get_key_with_most_items method is faster by almost 50%, with times 15.68s and 8.06s respectively. Could anyone recommend (if possible) something even faster?
The solution is extremely simple:
max(d, key=lambda x: len(d[x]))
Explanation:
dictionaries, when iterated, are just a set of keys. max(some_dictionary) will take maximum of keys
max optionally accepts a comparison function (key). To compare dictionary keys by the amount of items, the built-in len does just the job.
Use d.items() to get a sequence of the keys and values. Then get the max of this from the length of the values.
def get_key_with_most_items(d):
maxitem = max(d.items(), key = lambda item: len(item[1]))
return maxitem[0]
for the max function:
max(d, key=lambda k: len(d[k]))
If you want the dict to be ordered, then use OrderedDict. I think technically your code will still work with regular dict, but that's a technicality based on the current implementation of Pythons dict - In the past regular dict would not have reliable order, and in the future it may not.
You could do this for example as a one liner to turn your dict into an ordered dict by value length:
from collections import OrderedDict
ordered_dict = OrderedDict(sorted(d.items(), key=lambda t: len(t[1])))
for key, value in sorted(fdict.items(), key=lambda x: x[1], reverse=True):
print(key,value)
I've got this much for just the printing right now, but I am unsure as to how to approach only printing the first five keys and values rather than all of them.
Grab only the first 5 elements from the sorted list
for key, value in sorted(fdict.items(), key=lambda x: x[1], reverse=True)[:5]:
print(key,value)
You could use collections.Counter:
for key, value in Counter(fdict).most_common(5):
print(key, value)
Or heapq.nlargest:
for key, value in nlargest(5, fdict.items(), key=lambda x: x[1]):
print(key, value)
Add [:5] to the end of the array (I removed the .item() to clean things up a bit):
for k in sorted(fdict,key=lambda x:fdict[x],reverse=True)[:5]:
print(k,fdict[k])
So what I was trying to do was output the string "33k22k11k", which is just the last value followed by the reversed last key followed by the second last value followed by the second last reversed key and so on. I'm not sure how to get the reversed key value for the specific loop that I am in. From the code I currently I have, I get the output:
dict = {"k1":1, "k2":2, "k3":3}
current=""
current_k=""
for k,v in dict.items():
for i in k:
current_k=i+current_k
current=str(v)+current_k+current
print(current)
print(current_k)
33k2k1k22k1k11k
3k2k1k
Edited
First of all, if you are on python < 3.6, dict does not keep the order of items. You might want to use collections.OrderedDict for your purpose.
d = {"k1":1, "k2":2, "k3":3}
d.keys()
# dict_keys(['k2', 'k1', 'k3'])
whereas,
d = OrderedDict()
d['k1'] = 1
d['k2'] = 2
d['k3'] = 3
d.keys()
# odict_keys(['k1', 'k2', 'k3'])
With our new d, you can either add the key and values and reverse it:
res = ''
for k, v in d.items():
res += str(k) + str(v)
res[::-1]
# '33k22k11k'
or reversely iterate:
res = ''
for k, v in reversed(d.items()):
res += str(v)[::-1] + str(k)[::-1]
res
# '33k22k11k'
I may be wrong but it seems like you would want to reset the value of current_k each time you access a new key
dict = {"k1":1, "k2":2, "k3":3}
current=""
for k,v in dict.items():
current_k=""
for i in k:
current_k=i+current_k
current=str(v)+current_k+current
print(current)
print(current_k)
Why not simply do:
print(''.join([a+str(b) for a,b in dict.items()])[::-1])
Output:
"33k22k11k"
But if the values are different from the keys, do:
print(''.join([str(b)[::-1]+a for a,b in dict.items()[::-1]]))
You can use the Python map function to create the reversed string(using f-string) for each key/value pair and then join it.
dict1 = {"k1":1, "k2":2, "k3":3}
new_dict = "".join(map(lambda k, v: f'{k}{v}'[::-1] , dict1.keys(), dict1.values()))
Output:
33k22k11k
You can do something like this perhaps:
dict = {"k1":1, "k2":2, "k3":3}
print("".join(list(reversed([str(v)+"".join(reversed(k)) for k, v in dict.items()]))))
Output:
33k22k11k
I have a dict like this:
d = {'first':'', 'second':'', 'third':'value', 'fourth':''}
and I want to find first non-empty value (and it's name, in this example 'third'). There may be more than one non-empty value, but I only want the first one I find.
How can I do this?
Use an OrderedDict which preserves the order of elements. Then loop over them and find the first that isn't empty:
from collections import OrderedDict
d = OrderedDict()
# fill d
for key, value in d.items():
if value:
print(key, " is not empty!")
You could use next (dictionaries are unordered - this somewhat changed in Python 3.6 but that's only an implementation detail currently) to get one "not-empty" key-value pair:
>>> next((k, v) for k, v in d.items() if v)
('third', 'value')
Like this?
def none_empty_finder(dict):
for e in dict:
if dict[e] != '':
return [e,dict[e]]
d = {'first':'', 'second':'', 'third':'value', 'fourth':''}
for k, v in d.items():
if v!='':
return k, v
Edit 1
from the comment if the value is None or '' we better use if v: instead of if v!=''. if v!='' only check the '' and skip others
You can find empty elements and make a list of them:
non_empty_list = [(k,v) for k,v in a.items() if v]
By using list comprehension, you can list all the non-empty values and then fetch the 0th value:
[val for key, val in d.items() if val][0]
This question already has answers here:
How to sort a list with two keys but one in reverse order?
(8 answers)
Closed 28 days ago.
I have a dictionary of 200,000 items (the keys are strings and the values are integers).
What is the best/most pythonic way to print the items sorted by descending value then ascending key (i.e. a 2 key sort)?
a={ 'keyC':1, 'keyB':2, 'keyA':1 }
b = a.items()
b.sort( key=lambda a:a[0])
b.sort( key=lambda a:a[1], reverse=True )
print b
>>>[('keyB', 2), ('keyA', 1), ('keyC', 1)]
You can't sort dictionaries. You have to sort the list of items.
Previous versions were wrong. When you have a numeric value, it's easy to sort in reverse order. These will do that. But this isn't general. This only works because the value is numeric.
a = { 'key':1, 'another':2, 'key2':1 }
b= a.items()
b.sort( key=lambda a:(-a[1],a[0]) )
print b
Here's an alternative, using an explicit function instead of a lambda and the cmp instead of the key option.
def valueKeyCmp( a, b ):
return cmp( (-a[1], a[0]), (-b[1], b[0] ) )
b.sort( cmp= valueKeyCmp )
print b
The more general solution is actually two separate sorts
b.sort( key=lambda a:a[1], reverse=True )
b.sort( key=lambda a:a[0] )
print b
data = { 'keyC':1, 'keyB':2, 'keyA':1 }
for key, value in sorted(data.items(), key=lambda x: (-1*x[1], x[0])):
print key, value
The most pythonic way to do it would be to know a little more about the actual data -- specifically, the maximum value you can have -- and then do it like this:
def sortkey((k, v)):
return (maxval - v, k)
items = thedict.items()
items.sort(key=sortkey)
but unless you already know the maximum value, searching for the maximum value means looping through the dict an extra time (with max(thedict.itervalues())), which may be expensive. Alternatively, a keyfunc version of S.Lott's solution:
def sortkey((k, v)):
return (-v, k)
items = thedict.items()
items.sort(key=sortkey)
An alternative that doesn't care about the types would be a comparison function:
def sortcmp((ak, av), (bk, bv)):
# compare values 'in reverse'
r = cmp(bv, av)
if not r:
# and then keys normally
r = cmp(ak, bk)
return r
items = thedict.items()
items.sort(cmp=sortcmp)
and this solution actually works for any type of key and value that you want to mix ascending and descending sorting with in the same key. If you value brevity you can write sortcmp as:
def sortcmp((ak, av), (bk, bv)):
return cmp((bk, av), (ak, bv))
You can use something like this:
dic = {'aaa':1, 'aab':3, 'aaf':3, 'aac':2, 'aad':2, 'aae':4}
def sort_compare(a, b):
c = cmp(dic[b], dic[a])
if c != 0:
return c
return cmp(a, b)
for k in sorted(dic.keys(), cmp=sort_compare):
print k, dic[k]
Don't know how pythonic it is however :)
Building on Thomas Wouters and Ricardo Reyes solutions:
def combine(*cmps):
"""Sequence comparisons."""
def comparator(a, b):
for cmp in cmps:
result = cmp(a, b):
if result:
return result
return 0
return comparator
def reverse(cmp):
"""Invert a comparison."""
def comparator(a, b):
return cmp(b, a)
return comparator
def compare_nth(cmp, n):
"""Compare the n'th item from two sequences."""
def comparator(a, b):
return cmp(a[n], b[n])
return comparator
rev_val_key_cmp = combine(
# compare values, decreasing
reverse(compare_nth(1, cmp)),
# compare keys, increasing
compare_nth(0, cmp)
)
data = { 'keyC':1, 'keyB':2, 'keyA':1 }
for key, value in sorted(data.items(), cmp=rev_val_key_cmp):
print key, value
>>> keys = sorted(a, key=lambda k: (-a[k], k))
or
>>> keys = sorted(a)
>>> keys.sort(key=a.get, reverse=True)
then
print [(key, a[key]) for key in keys]
[('keyB', 2), ('keyA', 1), ('keyC', 1)]