该问题基于previous Stackoverflow answer。这个问题对我来说似乎太大了。
我现在有了排序功能sort_multi(lst, index_normal, index_reversed)
,它接受输入列表,还有两个参数,指示哪一列以正常顺序排序,哪一列反向:
from pprint import pprint
from itertools import groupby, chain
l = ((1, 'b'),
(1, 'd'),
(2, 'a'),
(1, 'a'))
def sort_multi(lst, index_normal, index_reversed):
return list(chain.from_iterable([sorted(list(j), key=lambda v:v[index_reversed], reverse=True) for i, j in groupby(sorted(lst), key=lambda v:v[index_normal])]))
pprint(sort_multi(l, 0, 1), width=10) # index 0 is sorted normally, 1 in reversed order.
输出:
[(1, 'd'),
(1, 'b'),
(1, 'a'),
(2, 'a')]
我想要的是扩展该功能以适用于任意个索引。例如
例如输入3列:
l = ((1, 'c', 'aa'),
(2, 'b', 'bb'),
(1, 'c', 'cc'),
(1, 'd', 'dd'))
sort_multi(l, reversed=(False, True, True))
给出输出:
[(1, 'd', 'dd'),
(1, 'c', 'cc'),
(1, 'c', 'aa'),
(2, 'b', 'bb')]
元组可以包含字符串,整数,...
答案 0 :(得分:2)
递归方法:按第一个条件对列表进行排序。然后按该标准分组,然后使用其余标准对每个子组进行递归排序。
from operator import itemgetter
import itertools
def multisorted(seq, indices, reversed_states):
if len(indices) == 0:
return seq
index = indices[0]
reversed = reversed_states[0]
partially_sorted_seq = sorted(seq, key = itemgetter(indices[0]), reverse=reversed_states[0])
result = []
for key, group in itertools.groupby(partially_sorted_seq, key=itemgetter(indices[0])):
result.extend(multisorted(group, indices[1:], reversed_states[1:]))
return result
d = ((1, 'c', 'aa'),
(2, 'b', 'bb'),
(1, 'c', 'cc'),
(1, 'd', 'dd'))
print(multisorted(d, (0,1,2), (False, True, True)))
结果:
[(1, 'd', 'dd'), (1, 'c', 'cc'), (1, 'c', 'aa'), (2, 'b', 'bb')]
方法2。 sort
和sorted
可以按多种标准进行开箱即用。我们只需要更改键,以使每个元组的某些元素在不平等比较方面具有相反的逻辑即可。
from functools import total_ordering
@total_ordering
class Negated:
def __init__(self, value):
self.value = value
def __eq__(self, other):
return self.value == other.value
def __lt__(self, other):
return self.value > other.value
def multisorted(seq, ordering):
return sorted(seq, key = lambda t: [Negated(x) if reversed else x for x, reversed in zip(t, ordering)])
d = ((1, 'c', 'aa'),
(2, 'b', 'bb'),
(1, 'c', 'cc'),
(1, 'd', 'dd'))
print(multisorted(d, (False, True, True)))
答案 1 :(得分:2)
您可以做一些更简单的事情:
from operator import itemgetter
def sort_any_multi(lst, index_order_reversed):
for index, reverse in reversed(index_order_reversed):
lst = sorted(lst, key=itemgetter(index), reverse=reverse)
return lst
r = ((1, 'c', 'aa'),
(2, 'b', 'bb'),
(1, 'c', 'cc'),
(1, 'd', 'dd'))
print(sort_any_multi(r, [[0, False], [1, True], [2, True]]))
送礼:
[(1, 'd', 'dd'), (1, 'c', 'cc'), (1, 'c', 'aa'), (2, 'b', 'bb')]
技巧是从最后一个优先级索引到最高优先级索引进行排序。