Rad*_*aKk 13 python sorting tuples list
我有一个元组列表to_order,如:
to_order = [(0, 1), (1, 3), (2, 2), (3,2)]
Run Code Online (Sandbox Code Playgroud)
以及一个列表,它给出了应用于每个元组的第二个元素的顺序to_order:
order = [2, 1, 3]
Run Code Online (Sandbox Code Playgroud)
所以我正在寻找一种获得此输出的方法:
ordered_list = [(2, 2), (3,2), (0, 1), (1, 3)]
Run Code Online (Sandbox Code Playgroud)
有任何想法吗?
alf*_*sin 20
您可以提供一个key将检查索引(第二个元素)order并根据它进行排序:
to_order = [(0, 1), (1, 3), (2, 2), (3,2)]
order = [2, 1, 3]
print(sorted(to_order, key=lambda item: order.index(item[1]))) # [(2, 2), (3, 2), (0, 1), (1, 3)]
Run Code Online (Sandbox Code Playgroud)
编辑
因为,关于时间复杂性的讨论开始了......在这里O(n+m),使用Eric的输入示例运行以下算法:
N = 5
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_sort(to_order, order):
bins = {}
for pair in to_order:
bins.setdefault(pair[1], []).append(pair)
return [pair for i in order for pair in bins[i]]
def alfasin_new_sort(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]
from timeit import timeit
print("eric_sort", timeit("eric_sort(to_order, order)", setup=setup, number=1000))
print("alfasin_new_sort", timeit("alfasin_new_sort(to_order, order)", setup=setup, number=1000))
Run Code Online (Sandbox Code Playgroud)
OUTPUT:
eric_sort 59.282021682999584
alfasin_new_sort 44.28244407700004
Run Code Online (Sandbox Code Playgroud)
Eri*_*nil 18
您可以根据第二个元素在列表的dict中分发元组,并迭代order索引以获取排序列表:
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)]
Run Code Online (Sandbox Code Playgroud)
sort或者index不需要,输出稳定.
该算法类似于mapping假设的副本中提到的.如果该链接的答案只能to_order与order具有相同的长度,这是不是在OP的问题的情况下.
该算法在每个元素上迭代两次to_order.复杂性是O(n).@ alfasin的第一个算法慢得多(O(n * m * log n)),但他的第二个算法也是O(n).
这是一个列表,在0和之间有10000个随机对1000.我们提取唯一的第二个元素并对它们进行洗牌以定义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
Run Code Online (Sandbox Code Playgroud)