Sorting a dict with tuples as values - python

I have a dictionary that looks like this:
{'key_info': (rank, raw_data1, raw_data2),
'key_info2': ...}
Basically I need back a list of the keys in sorted order, that is sorted based on the rank field in the tuple.
My code looks something like this right now (diffs is the name of the dict above):
def _sortRanked(self):
print(type(self.diffs))
return sorted(self.diffs.keys(), key=lambda x: x[1], reverse=True)
that right now returns this when I run it:
return sorted(self.diffs.keys(), key=lambda x: x[1], reverse=True)
IndexError: string index out of range

keys() only gives you keys, not values, so you have to use the keys to retrieve values from the dict if you want to sort on them:
return sorted(self.diffs.keys(), key=lambda x: self.diffs[x], reverse=True)
Since you're sorting on rank, which is the first item in the tuple, you don't need to specify which item in the value tuple you want to sort on. But if you wanted to sort on raw_data1:
return sorted(self.diffs.keys(), key=lambda x: self.diffs[x][1], reverse=True)

You're passing the key as the argument to, uh, key.
[k for (k, v) in sorted(D.iteritems(), key=lambda x: x[1], reverse=True)]

You're attempting to sort on the keys of the dictionary, not the values. Replace your self.diffs.keys() call with self.diffs.items(), and then it should work (but do keep the lambda, or use operator.itemgetter(1). Tuples sort starting with the first element, so you don't have to worry about that.)
Just noticed that you only want the keys. With my suggestion, you'd have to wrap the sort with zip()[0] (making sure to unpack the resultant list of tuples from the sort by prefixing with * in the call to zip()).

You're close. Try this instead:
return sorted(self.diffs.keys(), key = lambda x: self.diffs[x][0], reverse = True)
You're sorting a list of keys, so you have to take that key back to the dictionary and retrieve element 1 in order to use it as a comparison value.

Related

Using dictionaries in loop

I am trying to write a code that replicates greedy algorithm and for that I need to make sure that my calculations use the highest value possible. Potential values are presented in a dictionary and my goal is to use largest value first and then move on to lower values. However since dictionary values are not sequenced, in for loop I am getting unorganized sequences. For example, out put of below code would start from 25.
How can I make sure that my code is using a dictionary yet following the sequence of (500,100,25,10,5)?
a={"f":500,"o":100,"q":25,"d":10,"n":5}
for i in a:
print a[i]
Two ideas spring to mind:
Use collections.OrderedDict, a dictionary subclass which remembers the order in which items are added. As long as you add the pairs in descending value order, looping over this dict will return them in the right order.
If you can't be sure the items will be added to the dict in the right order, you could construct them by sorting:
Get the values of the dictionary with values()
Sort by (ascending) value: this is sorted(), and Python will default to sorting in ascending order
Get them by descending value instead: this is reverse=True
Here's an example:
for value in sorted(a.values(), reverse=True):
print value
Dictionaries yield their keys when you iterate them normally, but you can use the items() view to get tuples of the key and value. That'll be un-ordered, but you can then use sorted() on the "one-th" element of the tuples (the value) with reverse set to True:
a={"f":500,"o":100,"q":25,"d":10,"n":5}
for k, v in sorted(a.items(), key=operator.itemgetter(1), reverse=True):
print(v)
I'm guessing that you do actually need the keys, but if not, you can just use values() instead of items(): sorted(a.values(), reverse=True)
You can use this
>>> a={"f":500,"o":100,"q":25,"d":10,"n":5}
>>> for value in sorted(a.itervalues(),reverse=True):
... print value
...
500
100
25
10
5
>>>
a={"f":500,"o":100,"q":25,"d":10,"n":5}
k = sorted(a, key=a.__getitem__, reverse=True)
v = sorted(a.values(), reverse=True)
sorted_a = zip(k,v)
print (sorted_a)
Output:
[('f', 500), ('o', 100), ('q', 25), ('d', 10), ('n', 5)]

Sorting a list using two keys

I have a list of strings which i want to sort according to number of dots(.) in the given string and if the number of dots in those strings is equal i want them to be sorted by their length.(Both in descending order should not be a problem anyway)
The first part could be implemented easily
given_list.sort(key=dots,reverse=True)
dots function is implemented and it works fine.
This is where i am stuck as I am unable to sort the already sorted list according to their lengths if the number of dots is equal.
Which leads me to think i should somehow customize the key parameter using lambda, but it does not really work as it should , but it does in the case of nested lists or dictionaries .
how do i get this done?
You can pass in a custom lambda function to the sorted method as the sorting key.
In this case, I use a lambda x: (x.count("."), len(x)), which will create a composite key of count and length, and sort accordingly:
>>> given_list = ["e.x.a", "m.p.l.e", "ex.am.ple"]
>>> sorted(given_list, key=lambda x: (x.count("."), len(x)))
['e.x.a', 'ex.am.ple', 'm.p.l.e']
>>> sorted(given_list, key=lambda x: (x.count("."), len(x)), reverse=True)
['m.p.l.e', 'ex.am.ple', 'e.x.a']
Since you are using .sort, you can do the same here as well to sort the list in-place:
>>> given_list = ["e.x.a", "m.p.l.e", "ex.am.ple"]
>>> given_list.sort(key=lambda x: (x.count("."), len(x)), reverse=True)
>>> given_list
['m.p.l.e', 'ex.am.ple', 'e.x.a']

Sorting values in multiple lists

Currently, I have a list of lists called result which will contain values like this, for example:
result[1] = [John, 0.32]
result[2] = [Mikey, 1.90]
result[3] = [Sarah, 1.31]
result[4] = [Nancy, 0.49]
result[5] = [Billy, 0.13]
I want to however, sort this in descending order by the number which is held in the index space [1]. So the system will return the values in that order. Would I just have to use the sorted() function and call up the index where the value is held? I do not need to resort the list is it is necessary, i will just need to output the values in descending order.
How would I go about doing this exactly?
Use the key parameter in the sorted function.
sorted(result, key = lambda x:x[1], reverse = True)
The reverse = True makes sure that the items are sorted in the descending order. The important thing to be noted here is the key parameter.
key = lambda x:x[1]
We pass a lambda function to the key parameter, which accepts one parameter. sorted picks each element from result and pass that to the key function. In our case it is the tuples. The key function returns the second item in the tuples. So, the second item in the tuple will be used as the value of the tuple itself, while sorting. It means that when we comapre [John, 0.32] and [Mikey, 1.90], we will be actually comparing 0.32 and 1.90 only.
sorted doesn't change the actual list, but creates a new sorted list. But, if you want to sort the list itself, then you can use list.sort method, like this
result.sort(key = lambda x:x[1], reverse = True)
You can do that using sorted:
new_list = sorted(old_list, key=lambda x: x[1], reverse=True)
or using sort:
old_list.sort(key=lambda x: x[1], reverse=True)

Sort keys in dictionary by value in a list in Python

I have seen this post and this post as well as many others, but haven't quite found the answer to my question nor can I figure it out.
I have a dictionary of lists. For example it looks like:
Dict = {'a':[1,2,3,4], 'b':[9,8,7,6], 'c':[8,5,3,2]}
I want to return a list of the keys sorted (descending/reverse) based on a specific item in the lists. For example, I want to sort a,b,c based on the 4th item in each list.
This should return the list sorted_keys = ['b','a','c'] which were sorted by values [6,4,2].
Make sense? Please help...thanks!
Supply a key function, a lambda is easiest, and sort reversed:
sorted(Dict.keys(), key=lambda k: Dict[k][3], reverse=True)
The key function tells sorted what to sort by; the 4th item in the value for the given key.
Demo:
>>> sorted(Dict.keys(), key=lambda k: Dict[k][3], reverse=True)
['b', 'a', 'c']

sort dictionary of objects

I have a dictionary of objects where the key is a simple string, and the value is a data object with a few attributes. I'd like to sort my dictionary based on an attribute in the values of the dictionary. i have used this to sort based on the dictionaries values
sorted = dict.values()
sorted.sort(key = operator.attrgetter('total'), reverse=True)
This yields a sorted list of values (which is expected) and I lose my original keys from the dictionary (naturally). I would like to sort both the keys and values together... how can I achieve this? Any help would be greatly appreciated?
Use .items() (or its iterator version iteritems) instead of .values() to get a list of (key, value) tuples.
items = sorted(dct.iteritems(), key=lambda x: x[1].total, reverse=True)
You'll want to use .items() rather than .values(), for example:
def keyFromItem(func):
return lambda item: func(*item)
sorted(
dict.items(),
key=keyFromItem( lambda k,v: (v['total'], k) )
)
The above will sort first based on total, and for items with equal total, will sort them alphabetically by key. It will return items as (key,value) pairs, which you could just do [x[1] for x in sorted(...)] to get the values.
Use items instead of values - and a just use a lambda to fecth the sorting key itself, since there won't be a ready made operator for it:
sorted = dict.items()
sorted.sort(key = lambda item: item[1].total, reverse=True)

Categories

Resources