我正在尝试使用Python的sorted
函数对列表进行排序。在Python 3中删除了cmp
关键字参数。不幸的是,似乎我无法使用key
关键字参数实现我的算法,因为我需要两个对象才能比较数据。
示例已排序数据
59 59
59 3 1 1
59 4 3 3
61 1
61 10
61 237
61 1 1 1
比较功能
NUM_RE = re.compile("[\d]+")
def compare(x, y):
# Aggregate our data into integer arrays
x_result = [int(x) for x in NUM_RE.findall(x)]
y_result = [int(y) for y in NUM_RE.findall(y)]
# Return if there is a non-zero difference in the first element
statement_diff = x_result[0] - y_result[0]
if statement_diff != 0:
return statement_diff
# Return if there is a non-zero difference between the lengths
length_diff = len(x_result) - len(y_result)
if length_diff != 0:
return length_diff
# len(x_result) == len(y_result)
# Iterate over each item and return if there is a difference
for i in range(1, len(x_result)):
result = x_result[i] - y_result[i]
if result != 0:
return result
# Results are the same
return 0
排序此数据的最佳方法是什么?我应该创建一个实现__eq___
,__gt__
,__lt__
等功能的“包装器对象”,以便我可以使用默认的排序功能吗?或者标准Python API中是否包含另一个函数来完成sorted
的原始行为?
答案 0 :(得分:5)
Python已经有你描述的包装器,它被称为functools.cmp_to_key
答案 1 :(得分:3)
事实上,这很容易实现为关键功能。比较函数的行为就像字符串已转换为列表一样。所以它就像将字符串转换为数字列表一样简单:
NUM_RE = re.compile("[\d]+")
def seq_key(x):
return [int(y) for y in NUM_RE.findall(x)]
如果您对此感到不确定,请尝试此测试:
cmp_key = functools.cmp_to_key(compare)
def gen_rnd(n):
seq = [[random.randrange(1, 100)
for _ in xrange(random.randrange(2, 6))]
for _ in xrange(n)]
return [' '.join(map(str, x)) for x in seq]
def test(n):
a = gen_rnd(n)
return all(sorted(x, key=seq_key) == sorted(x, key=cmp_key)
for x in a)
test(1000000)
此测试不检查极端情况,但我非常确定它们在语义上是相同的。
您可能会问“为什么要麻烦地找出正确的key
功能?”原因如下:
>>> a = gen_rnd(10000)
>>> %timeit sorted(a, key=cmp_key)
1 loops, best of 3: 705 ms per loop
>>> %timeit sorted(a, key=seq_key)
10 loops, best of 3: 47.9 ms per loop
关键功能要快一个数量级!列表越大,效果越明显。这部分是因为列表比较是一种快速内置功能。但这也是因为真正的工作要少得多。执行的比较的数量为O(n log n),但执行的密钥转换次数仅为O(n)。因此,如果您可以将一些比较工作转换为关键功能,那么您可以获得良好的加速。