I've used the following approach many times to generate a list of tuples from the contents of a dictionary:
dispositions = list(dispositions.items())
In this case, the keys are different types of ways a patient can leave the emergency department, and the values are counts of those types. Now, I wanted to sort this data based on the second item in each of the tuples, so I tried this:
dispositions = list(dispositions.items()).sort(key=lambda x: x[1])
To my surprise, when I ran the code, I found that dispositions had been set to None. I tried breaking it into two parts, as follows:
dispositions = list(dispositions.items())
dispositions.sort(key=lambda x: x[1])
This works! I got my list of sorted tuples. So, I've already solved my problem, but I want to know why the first option didn't work so that I can be a better person (better programmers are better people). Can anyone help me out here?
list.sort does not return anything. So this:
dispositions = list(dispositions.items()).sort(key=lambda x: x[1])
sets dispositions to None.
sorted on the other hand returns a new list. So you would use:
dispositions = sorted(dispositions.items(), key=lambda x: x[1])
Which will set dispositions to a sorted list of tuples.
The sort function doesn't work like you might think. It does not return a sorted list, it directly modifies the list so it's sorted.
For instance, say you have this code:
a = [0, 2, 1]
a.sort()
a will now be changed [0, 1, 2]. Had I used a = a.sort() rather than just a.sort(), it would have been set to None.
This:
dispositions = list(dispositions.items()).sort(key=lambda x: x[1])
functions the same as this:
dispositions = list(dispositions.items())
dispositions = dispositions.sort(key=lambda x: x[1])
Which sets dispositions to the returned value from sort, which is None.
On the other hand, this:
dispositions = list(dispositions.items())
dispositions.sort(key=lambda x: x[1])
is not setting dispositions to the value of sort, it's simply calling the sort function on dispositions, which causes the list to be sorted as intended.
Related
I have a list with 2 or 3 character strings with the last character being the same.
example_list = ['h1','ee1','hi1','ol1','b1','ol1','b1']
is there any way to sort this list using the order of another list.
order_list = ['ee','hi','h','b','ol']
So the answer should be something like example_list.sort(use_order_of=order_list)
Which should produce an output like ['ee1','hi1','h1','b1','b1','ol1','ol1']
I have found other questions on StackOverflow but I am still unable find a answer with a good explanation.
You could build an order_map that maps the prefixes to their sorting key, and then use that map for the key when calling sorted:
example_list = ['h1','ee1','hi1','ol1','b1','ol1','b1']
order_list = ['ee','hi','h','b','ol']
order_map = {x: i for i, x in enumerate(order_list)}
sorted(example_list, key=lambda x: order_map[x[:-1]])
This has an advantage over calling order_list.index for each element, as fetching elements from the dictionary is fast.
You can also make it work with elements that are missing from the order_list by using dict.get with a default value. If the default value is small (e.g. -1) then the values that don't appear in order_list will be put at the front of the sorted list. If the default value is large (e.g. float('inf')) then the values that don't appear in order_list will be put at the back of the sorted list.
You can use sorted with key using until the last string of each element in example_list:
sorted(example_list, key=lambda x: order_list.index(x[:-1]))
Ourput:
['ee1', 'hi1', 'h1', 'b1', 'b1', 'ol1', 'ol1']
Note that this assumes all element in example_list without the last character is in order_list
Something like this? It has the advantage of handling duplicates.
sorted_list = [
i
for i, _
in sorted(zip(example_list, order_list), key=lambda x: x[1])
]
I need to sort nested lists based on the first element in each list...
So I have the following:
input = [['ABCMeter', 'six', 'page','car=frog'],['ABCarrow','mall','cop''xmlVal'],['ABCcomp','eleven','computer'],['ABCliz','one']]
I need them sorted such that:
output = [['ABCarrow','mall','cop''xmlVal'], ['ABCcomp','eleven','computer'], ['ABCliz','one'], ['ABCMeter', 'six', 'page','car=frog']]
I have tried the following with no luck (and several other sort methods):
split_into_lists = input.sort(key=lambda x: x[0])
You are just using the wrong function; the sort method modifies the list in-place and returns None. Use sorted instead to return a new list.
split_into_lists = sorted(input, key=lambda x: x[0])
Also, the expected output doesn't match the sort criteria of String objects.
For example:
ABCMeter < ABCarrow
It compares character by character, and if they are equal, it compares the next one. Since M is less than a (see ASCII Table), ABCMeter < ABCarrow
split_into_lists = sorted(input, key=lambda x: x[0].casefold())
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']
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)
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.