1

I am trying to sort todo as per the order in priority

>>> todo
['see doctor', 'do assignment', 'pay rent', 'check bank account', 'clean room']

>>> priority
[3, 4, 1, 2, 5]

>>> todo.sort(key=lambda x: priority[todo.index(x)])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 1, in <lambda>
ValueError: 'see doctor' is not in list

Why am I getting this error when trying to sort todo like this ?

Works with sorted though:

>>> sorted(todo, key=lambda x: priority[todo.index(x)])
['pay rent', 'check bank account', 'see doctor', 'do assignment', 'clean room']

Why does it work with sorted but not with sort?

Ankur Agarwal
  • 23,692
  • 41
  • 137
  • 208
  • Possible duplicate of [Sorting list based on values from another list?](http://stackoverflow.com/questions/6618515/sorting-list-based-on-values-from-another-list) – Bhargav Rao Jan 11 '16 at 05:51
  • 1
    @BhargavRao Yes and no: the solution is the same, and essentially the problem as well. The duplicate question however, despite multiple answers, does not explain *why* the OP gets the error they get. –  Jan 11 '16 at 05:53
  • @Evert Exactly. I understand how to sort based on key. My question here is why am I getting the error in this particular case. – Ankur Agarwal Jan 11 '16 at 07:24

2 Answers2

3

Well, you can simply zip() the 2 list and then sort it on the basis of priority by using sorted().

>>> todo = ['see doctor', 'do assignment', 'pay rent', 'check bank account', 'clean room']
>>> priority = [3, 4, 1, 2, 5]
>>> [y for (x,y) in sorted(zip(priority, todo))]
['pay rent', 'check bank account', 'see doctor', 'do assignment', 'clean room']

EDIT: The reason as to why you are getting the error ValueError: 'see doctor' is not in list is because there is a difference between using list.sort() and the built-in function sorted().

sorted() returns a new sorted list, leaving the original list unaffected. list.sort() sorts the list in-place, mutating the list indices.

You can refer this answer for more clarification regarding the difference.

If you refer the source code for list.sort() (the listsort() function), you'll notice a comment within the function that says -

The list is temporarily made empty, so that mutations performed by comparison functions can't affect the slice of memory we're sorting.

Hence, when the lambda function executes, it tries to find the index of 'see doctor' in the list (from todo.index(x)). But since the list is empty, it returns the ValueError: 'see doctor' is not in list.

This error is not thrown for sorted() because it initializes a new empty list and then appends the strings into the newly created list without modify the given list (i.e. todo).

Source code for list.sort() and sorted().

Community
  • 1
  • 1
JRodDynamite
  • 12,325
  • 5
  • 43
  • 63
2

Jason has given you the (better) solution (or go numpy and use numpy array indexing; even simpler).

As to why you get that error: you're sorting todo in-place in your first code; at the same time, you ask for todo, thus you're asking for a list that's being altered in-place. That's not a good idea.
sorted() works, because a copy of todo is made first, and that copy is sorted, so .index() is still called on the original todo.


With numpy:

>>> todo = np.array(todo)
>>> priority = np.array(priority) - 1  # Python is 0-based
>>> todo[priority]
array(['pay rent', 'check bank account', 'see doctor', 'do assignment',
   'clean room'], dtype='|S18')
>>> print(todo[priority])
['pay rent' 'check bank account' 'see doctor' 'do assignment' 'clean room']