Sort list of tuples based on another list
You can use sorted
with an appropriate key
function:
l1 = [(1, 'a', 'x'), (2, 'b', 'y'), (3, 'a', 'z'), (4, 'c', 'xyz')]
l2 = ['a', 'b', 'c']
d2 = {v: i for i, v in enumerate(l2)} # map elements to indexes
# {'a': 0, 'b': 1, 'c': 2}
sorted(l1, key=lambda x: d2[x[1]])
# [(1, 'a', 'x'), (3, 'a', 'z'), (2, 'b', 'y'), (4, 'c', 'xyz')]
Sort tuple list with another list
Algorithm
You can distribute the tuples in a dict of lists according to the second element and iterate over order
indices to get the sorted list:
from collections import defaultdict
to_order = [(0, 1), (1, 3), (2, 2), (3, 2)]
order = [2, 1, 3]
bins = defaultdict(list)
for pair in to_order:
bins[pair[1]].append(pair)
print(bins)
# defaultdict(<class 'list'>, {1: [(0, 1)], 3: [(1, 3)], 2: [(2, 2), (3, 2)]})
print([pair for i in order for pair in bins[i]])
# [(2, 2), (3, 2), (0, 1), (1, 3)]
sort
or index
aren't needed and the output is stable.
This algorithm is similar to the mapping
mentioned in the supposed duplicate. This linked answer only works if to_order
and order
have the same lengths, which isn't the case in OP's question.
Performance
This algorithm iterates twice over each element of to_order
. The complexity is O(n)
. @alfasin's first algorithm is much slower (O(n * m * log n)
), but his second one is also O(n)
.
Here's a list with 10000 random pairs between 0
and 1000
. We extract the unique second elements and shuffle them in order to define order
:
from random import randrange, shuffle
from collections import defaultdict
from timeit import timeit
from itertools import chain
N = 1000
to_order = [(randrange(N), randrange(N)) for _ in range(10*N)]
order = list(set(pair[1] for pair in to_order))
shuffle(order)
def eric(to_order, order):
bins = defaultdict(list)
for pair in to_order:
bins[pair[1]].append(pair)
return list(chain.from_iterable(bins[i] for i in order))
def alfasin1(to_order, order):
arr = [[] for i in range(len(order))]
d = {k:v for v, k in enumerate(order)}
for item in to_order:
arr[d[item[1]]].append(item)
return [item for sublist in arr for item in sublist]
def alfasin2(to_order, order):
return sorted(to_order, key=lambda item: order.index(item[1]))
print(eric(to_order, order) == alfasin1(to_order, order))
# True
print(eric(to_order, order) == alfasin2(to_order, order))
# True
print("eric", timeit("eric(to_order, order)", globals=globals(), number=100))
# eric 0.3117517130003762
print("alfasin1", timeit("alfasin1(to_order, order)", globals=globals(), number=100))
# alfasin1 0.36100843100030033
print("alfasin2", timeit("alfasin2(to_order, order)", globals=globals(), number=100))
# alfasin2 15.031453827000405
How to sort a list/tuple of lists/tuples by the element at a given index?
sorted_by_second = sorted(data, key=lambda tup: tup[1])
or:
data.sort(key=lambda tup: tup[1]) # sorts in place
The default sort mode is ascending. To sort in descending order use the option reverse=True
:
sorted_by_second = sorted(data, key=lambda tup: tup[1], reverse=True)
or:
data.sort(key=lambda tup: tup[1], reverse=True) # sorts in place
How to sort a list of tuples according to another list
a.sort(key=lambda x: b.index(x[0]))
This sorts a
in-place using the the index in b
of the first element of each tuple from a
as the values it sorts on.
Another, possibly cleaner, way of writing it would be:
a.sort(key=lambda (x,y): b.index(x))
If you had large numbers of items, it might be more efficient to do things a bit differently, because .index()
can be an expensive operation on a long list, and you don't actually need to do a full sorting since you already know the order:
mapping = dict(a)
a[:] = [(x,mapping[x]) for x in b]
Note that this will only work for a list of 2-tuples. If you want it to work for arbitrary-length tuples, you'd need to modify it slightly:
mapping = dict((x[0], x[1:]) for x in a)
a[:] = [(x,) + mapping[x] for x in b]
how to sort a list of tuples based on another list
You can use sorted
function, just like below.
sorted(Y, key=lambda a: (a[1], X.index(a[0])))
The order of keys is (Y based number, X based character).
Sort a list of tuples by 2nd item (integer value)
Try using the key
keyword with sorted()
.
sorted(
[('abc', 121), ('abc', 231), ('abc', 148), ('abc', 221)],
key=lambda x: x[1]
)
key
should be a function that identifies how to retrieve the comparable element from your data structure. In your case, it is the second element of the tuple, so we access [1]
.
For optimization, see jamylak's response using itemgetter(1)
, which is essentially a faster version of lambda x: x[1]
.
Sorting a list of tuples in different order based on the values of a tuple
You can change the signs in the tuples' values to get the expected behaviour:
ts.sort(key=lambda t: (t[0], -t[1], -t[2]))
print(ts)
# [(3, 12, 9), (3, 12, 8), (4, 22, 17), (4, 5, 7), (4, 5, 6), (7, 14, 5),
# (20, 23, 24), (20, 22, 8)]
For the general case, you can map the the increasing', 'decreasing'...
list to sings and zip
each tuple in the key
with the signs as:
l = ('increasing', 'decreasing', 'decreasing')
d = {'increasing':1, 'decreasing':-1}
signs = [d[i] for i in l]
ts.sort(key = lambda x: tuple(i*sign for sign,i in zip(signs, x)))
Which would yield the same as above:
print(ts)
# [(3, 12, 9), (3, 12, 8), (4, 22, 17), (4, 5, 7), (4, 5, 6), (7, 14, 5),
# (20, 23, 24), (20, 22, 8)]
Related Topics
Check If a File Is Not Open Nor Being Used by Another Process
How to Convert a Given Ordinal Number (From Excel) to a Date
How to Print Bold Text in Python
Get Lat/Long Given Current Point, Distance and Bearing
Python: How to Make the Ansi Escape Codes to Work Also in Windows
How to Save an Image Locally Using Python Whose Url Address I Already Know
How to Set Timeout on Python's Socket Recv Method
Monitoring Contents of Files/Directories
How to Load a Module from Code in a String
Complexity of *In* Operator in Python
Repeat Rows in a Pandas Dataframe Based on Column Value
Compute a Confidence Interval from Sample Data
Pip Installing in Global Site-Packages Instead of Virtualenv
How to Redirect Stdout and Stderr to Logger in Python
Adding a Background Image to a Plot