在了解python的时候发现Schwartzian transform这条规则,是针对computing intensive排序的一种高效手段,也被称作“装饰-排序-去装饰”(decorate-sort-undecorate),在Knuth的神作有详细介绍(当然我没有去翻)
一般地,在python的排序中, 我们提供一个compare函数,然后交由python内建的sort处理,比如
def
cmp(a,b):
if a > b: return 1
elif a < b: return - 1
else : return 0
if __name__ == ' __main__ ' :
ls = [ 1 , 8 , 5 , 3 ]
ls.sort(cmp)
print ls
if a > b: return 1
elif a < b: return - 1
else : return 0
if __name__ == ' __main__ ' :
ls = [ 1 , 8 , 5 , 3 ]
ls.sort(cmp)
print ls
你将会得到排好序的[1,3,5,8]
但是,有时如果cmp过于复杂,直接这样做效率会很低,于是 Schwartzian transform这种最早出现在perl中的编程惯例便显现出优越性,它的主要思想是:
1. 对list中的复杂元素进行处理,提取出与排序相关的key,与原元素组合成为tupple
2.调用内建排序算法(对key)
3.提取出排好序的list
以下是伪代码:
def sortDSU(list)
tmp = [(x.key(), x) for x in list] #这里key()表示提取排序相关的key值
tmp.sort()
return [x[ 1 ] for x in tmp]
tmp = [(x.key(), x) for x in list] #这里key()表示提取排序相关的key值
tmp.sort()
return [x[ 1 ] for x in tmp]
当然如果你想实现in-place排序,最后一句换为
list[:]
=
[x[
1
]
for
x
in
tmp]
========================================================
总结:
DSU避免了对复杂元素反复计算key值,达到了memoization的效果
最后,贴一个python cookbook上的例子:
Sorting a List of Objects by an Attribute of the Objects
按照指定属性排序
def
sort_by_attr(seq, attr):
import operator
intermed = map(None, map(getattr, seq, (attr,) * len(seq)),
xrange(len(seq)), seq)
intermed.sort( )
return map(operator.getitem, intermed, ( - 1 ,) * len(intermed))
import operator
intermed = map(None, map(getattr, seq, (attr,) * len(seq)),
xrange(len(seq)), seq)
intermed.sort( )
return map(operator.getitem, intermed, ( - 1 ,) * len(intermed))
如果对map不是很熟,另一种表述可能会更清晰
def
sort_by_attr2(seq, attr):
intermed = [(getattr(seq[i], attr), i, seq[i]) for i in xrange(len(seq))]
intermed.sort( )
return [ tup[ - 1 ] for tup in intermed ]
intermed = [(getattr(seq[i], attr), i, seq[i]) for i in xrange(len(seq))]
intermed.sort( )
return [ tup[ - 1 ] for tup in intermed ]