-1

I have a dictionary with the following structure:

Key   = A tuple containing two strings
Value = A tuple containing two float values

I want to sort this dictionary using both values.

The requirement is to pick the top 10 records with maximum values for both float fields

Is it possible to do so?

Please find below a sample of the data in dictionary:

{"(12144, 'DBI 3900288')(62232, 'DBI 9503371')": (0.2978723404255319, 56),
 "(62232, 'DBI 9503371')(12144, 'DBI 3900288')": (0.45153846153846154, 56),
 "(89121, 'USB 7812')(908121, 'USB 3182')": (0.45, 6),
 "(908121, 'USB 3182')(20629, 'FORT 11156')": (0.8, 8),
 "(908121, 'USB 3182')(20630, 'FORT 11158')": (0.9, 9),
 "(908121, 'USB 3182')(20632, 'FORT 11164')": (0.45, 6),
 "(908121, 'USB 3182')(20666, 'FORT 1234TOB')": (0.8, 8),
 "(908121, 'USB 3182')(20667, 'FORT 1236TOB')": (0.45, 6),
 "(908121, 'USB 3182')(20669, 'FORT 1240TOB')": (0.8, 8),
 "(908121, 'USB 3182')(20674, 'FORT 1252TOB')": (0.8, 8),
 "(908121, 'USB 3182')(20675, 'FORT 1258TOB')": (0.8, 8),
 "(908121, 'USB 3182')(20684, 'FORT 13408A')": (0.7, 7),
 "(908121, 'USB 3182')(20685, 'FORT 13410A')": (0.7, 7),
 "(908121, 'USB 3182')(20686, 'FORT 13412A')": (0.45, 6),
 "(908121, 'USB 3182')(20687, 'FORT 13415A')": (0.45, 6),
 "(908121, 'USB 3182')(20688, 'FORT 13418A')": (0.45, 6),
 "(908121, 'USB 3182')(20689, 'FORT 13424A')": (0.45, 6),
 "(908121, 'USB 3182')(20711, 'FORT 16-630')": (0.8, 8),
 "(908121, 'USB 3182')(20712, 'FORT 16-632')": (0.7, 7),
 "(908121, 'USB 3182')(20713, 'FORT 16-634')": (0.45, 6),
 "(908121, 'USB 3182')(20714, 'FORT 16-636')": (0.7, 7),
 "(908121, 'USB 3182')(20716, 'FORT 16-640')": (0.8, 8),
 "(908121, 'USB 3182')(20972, 'FORT 39002')": (0.9, 9),
 "(908121, 'USB 3182')(20985, 'FORT 39652')": (0.8, 8),
 "(908121, 'USB 3182')(20987, 'FORT 39658')": (0.7, 7),
 "(908121, 'USB 3182')(20992, 'FORT 39670')": (0.7, 7),
 "(908121, 'USB 3182')(20993, 'FORT 39672')": (0.45, 6),
 "(908121, 'USB 3182')(20995, 'FORT 39676')": (0.7, 7),
 "(908121, 'USB 3182')(20996, 'FORT 39682')": (0.7, 7),
 "(908121, 'USB 3182')(20999, 'FORT 39688')": (0.45, 6) }

Expected Output:

{

 "(908121, 'USB 3182')(20630, 'FORT 11158')": (0.9, 9),
 "(908121, 'USB 3182')(20972, 'FORT 39002')": (0.9, 9),
 "(908121, 'USB 3182')(20629, 'FORT 11156')": (0.8, 8),
 "(908121, 'USB 3182')(20666, 'FORT 1234TOB')": (0.8, 8),
 "(908121, 'USB 3182')(20669, 'FORT 1240TOB')": (0.8, 8),
 "(908121, 'USB 3182')(20674, 'FORT 1252TOB')": (0.8, 8),
 "(908121, 'USB 3182')(20675, 'FORT 1258TOB')": (0.8, 8),
 "(908121, 'USB 3182')(20711, 'FORT 16-630')": (0.8, 8),
 "(908121, 'USB 3182')(20716, 'FORT 16-640')": (0.8, 8),
 "(908121, 'USB 3182')(20985, 'FORT 39652')": (0.8, 8),
 "(908121, 'USB 3182')(20684, 'FORT 13408A')": (0.7, 7),
 "(908121, 'USB 3182')(20685, 'FORT 13410A')": (0.7, 7),
 "(908121, 'USB 3182')(20712, 'FORT 16-632')": (0.7, 7),
 "(908121, 'USB 3182')(20714, 'FORT 16-636')": (0.7, 7),
 "(908121, 'USB 3182')(20995, 'FORT 39676')": (0.7, 7),
 "(908121, 'USB 3182')(20996, 'FORT 39682')": (0.7, 7),
 "(908121, 'USB 3182')(20987, 'FORT 39658')": (0.7, 7),
 "(908121, 'USB 3182')(20992, 'FORT 39670')": (0.7, 7), 
"(62232, 'DBI 9503371')(12144, 'DBI 3900288')": (0.45153846153846154, 56),
 "(908121, 'USB 3182')(20632, 'FORT 11164')": (0.45, 6),
 "(89121, 'USB 7812')(908121, 'USB 3182')": (0.45, 6),
 "(908121, 'USB 3182')(20667, 'FORT 1236TOB')": (0.45, 6),
 "(908121, 'USB 3182')(20686, 'FORT 13412A')": (0.45, 6),
 "(908121, 'USB 3182')(20687, 'FORT 13415A')": (0.45, 6),
 "(908121, 'USB 3182')(20688, 'FORT 13418A')": (0.45, 6),
 "(908121, 'USB 3182')(20689, 'FORT 13424A')": (0.45, 6),
 "(908121, 'USB 3182')(20713, 'FORT 16-634')": (0.45, 6),
 "(908121, 'USB 3182')(20999, 'FORT 39688')": (0.45, 6),
 "(908121, 'USB 3182')(20993, 'FORT 39672')": (0.45, 6)
 "(12144, 'DBI 3900288')(62232, 'DBI 9503371')": (0.2978723404255319, 56),
 }

When the sorting method is used on the float values of the tuple. The sorting order is sometimes mixed up when the second float value in the tuple is double digit. For e.g. in the example shown below, sorting of 1st float is perfectly in desc order, however, the second float sorting is incorrect as 8 < 15

 "(12423, 'LACT 1281')(14961, 'OSI 76214')": (0.8888888888888888, 8),
 "(12423, 'LACT 1281')(15328, 'PER 58835')": (0.8888888888888888, 8),
 "(12423, 'LACT 1281')(16902, 'RAP NRT16')": (0.8888888888888888, 8),
 "(18154, 'TGIS 804176-01')(18139, 'TGIS 57264-00')": (0.8823529411764706, 15),
 "(3034, 'TIME 08121')(2926, 'TIME 15677')": (0.8823529411764706, 15),
 "(3034, 'TIME 08121')(2927, 'TIME 16424')": (0.8823529411764706, 15),
blackbug
  • 1,098
  • 3
  • 13
  • 40
  • What exactly do you mean with "sorted by using both values"? Sorted by the first and then sorted by the second? – Sebastian Baltser Apr 05 '21 at 13:44
  • Yes, the requirement is actually to pick the top 10 records with maximum values for both float fields – blackbug Apr 05 '21 at 13:48
  • After submitting my answer I have become uncertain as to what you mean by the above comment. Can you provide an example of your desired output? – Sebastian Baltser Apr 05 '21 at 14:16
  • So you would like to sort by the maximum value of the tuple? – Sebastian Baltser Apr 05 '21 at 14:54
  • I added an example but I am not sure how the first two lines in the expected output should be sorted. Whenever there is a double-digit number in the second float position, the sorting is mixed up. Added an example of such mixup in the post as well. – blackbug Apr 05 '21 at 14:57
  • @SebastianBaltser Yes, but condition of max value should be set on both. So far I think the data has a pattern that both values are linear, thus sorting order should be respected. – blackbug Apr 05 '21 at 15:01
  • @SebastianBaltser Sorry for the confusion. The expected output is updated. The sorting should be as per the first value in the tuple only. – blackbug Apr 05 '21 at 18:24
  • No problem, but then my answer should be working if you use the reverse argument as described! – Sebastian Baltser Apr 05 '21 at 19:18

1 Answers1

1

The items-method returns an iterable with tuples containing the key/value-pairs. This iterable should be sorted by assessing the second element (index 1) in each tuple, i.e. the value of each dict-element. The following uses the key argument of the built-in function sorted with the value of operator.itemgetter(1). operator.itemgetter(1) returns a callable that fetches the item at index 1 from its argument. After sorting the iterable we can construct a dict from it:

from operator import itemgetter
ordered = sorted(data.items(), key=itemgetter(1))
dict(ordered)

The same can be achieved without using itemgetter by using a lambda-function that fetches the item at index 1:

ordered = sorted(data.items(), key=lambda x: x[1])
dict(ordered)

I recommend the first way though since itemgetter is faster than the lambda-function.

In case you would like to sort from high to low use the reverse argument of the sorted-function: sorted(..., reverse=True)

Please be aware of how tuples are compared:

Collections that support order comparison are ordered the same as their first unequal elements (for example, [1,2,x] <= [1,2,y] has the same value as x <= y).