Python自定义排序

时间:2015-06-12 20:22:31

标签: python sorting python-3.x

我正在尝试使用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的原始行为?

2 个答案:

答案 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)。因此,如果您可以将一些比较工作转换为关键功能,那么您可以获得良好的加速。