I have a list of strings like this:
X = [\"a\", \"b\", \"c\", \"d\", \"e\", \"f\", \"g\", \"h\", \"i\"]
Y = [ 0, 1, 1, 0, 1, 2, 2, 0, 1 ]
This is an old question but some of the answers I see posted don't actually work because zip
is not scriptable. Other answers didn't bother to import operator
and provide more info about this module and its benefits here.
There are at least two good idioms for this problem. Starting with the example input you provided:
X = ["a", "b", "c", "d", "e", "f", "g", "h", "i"]
Y = [ 0, 1, 1, 0, 1, 2, 2, 0, 1 ]
This is also known as the Schwartzian_transform after R. Schwartz who popularized this pattern in Perl in the 90s:
# Zip (decorate), sort and unzip (undecorate).
# Converting to list to script the output and extract X
list(zip(*(sorted(zip(Y,X)))))[1]
# Results in: ('a', 'd', 'h', 'b', 'c', 'e', 'i', 'f', 'g')
Note that in this case Y
and X
are sorted and compared lexicographically. That is, the first items (from Y
) are compared; and if they are the same then the second items (from X
) are compared, and so on. This can create unstable outputs unless you include the original list indices for the lexicographic ordering to keep duplicates in their original order.
This gives you more direct control over how to sort the input, so you can get sorting stability by simply stating the specific key to sort by. See more examples here.
import operator
# Sort by Y (1) and extract X [0]
list(zip(*sorted(zip(X,Y), key=operator.itemgetter(1))))[0]
# Results in: ('a', 'd', 'h', 'b', 'c', 'e', 'i', 'f', 'g')