3

我有一个必须排序的数据列表,遗憾的是这些对象的命名方案不是很一致。数据是一个字符串列表,这些字符串通常是实数,但有时末尾有一个字母。此列表中可接受值的一些示例如下所示:

# this is how it should be sorted
['1', '1.1', '1.2', '2', '2.1A', '2.1B', '2.2A', '101.1', '101.2']

由于这些在数据库中,我的第一个想法是使用以下 django 方法返回排序后的结果,但它返回如下。

#took out unneeded code
choices = [l.number for l in Locker.objects.extra(
               select={'asnumber': 'CAST(number as BYTEA)'}).order_by('asnumber')]
print choices
==> ['1', '1.1', '101.1', '101.2', '2', '2.1A', '2.1B', '2.2A']

遗憾的是,它无法按应有的方式对其进行排序。所以我的新计划是编写一个可以与 pythonsorted方法一起使用的方法,但我仍然不确定如何编写这个。我需要找到一种按字符串的实数部分排序的方法,然后作为辅助排序,按末尾附加的字母排序。

关于去哪里的任何建议?

4

5 回答 5

4

让 DBMS 做排序,这是它非常擅长的。您几乎无法与您的应用程序的性能相媲美。

如果你得到的只是带有 A 或 B 的小数,你可以简单地:

SELECT *
FROM  (
   SELECT unnest(
    ARRAY['1', '1.1', '1.2', '2', '2.1A', '2.1B', '2.2A', '101.1', '101.2']) AS s
   ) x
ORDER  BY rtrim(s, 'AB')::numeric, s;

完全按照要求订购,而且速度也很快。带有ARRAYand的子选择unnest()仅用于构建快速测试用例。ORDER BY条款是最重要的——在rtrim()手册中

如果涉及其他角色,您可能需要更新您的问题以完成图片。

于 2012-04-25T00:40:09.890 回答
2
x = ['1', '1.1', '1.2', '2', '2.1A', '2.1B', '2.2A', '101.1', '101.2']

#sort by the real number portion

import string

letters = tuple(string.ascii_letters)

def change(x):
    if x.endswith(letters):
        return float(x[:len(x) -1])
    else:
        return float(x)

my_list = sorted(x, key = lambda k: change(k))

结果:

>>> my_list
['1', '1.1', '1.2', '2', '2.1A', '2.1B', '2.2A', '101.1', '101.2']
于 2012-04-24T23:04:39.080 回答
0

最后我过早地概括为任意数量的字母:

from itertools import takewhile

def sort_key(value):
    cut_point = len(value) - len(list(takewhile(str.isalpha, reversed(value))))
    return (float(value[:cut_point]), value[cut_point:])

sorted((
    l.number
    for l in Locker.objects.extra(select={'asnumber': 'CAST(number as BYTEA)'})
), key = sort_key)
于 2012-04-24T22:53:03.470 回答
0

将字符串拆分为元组 - 一个实数(将其转换为浮点数或十进制数)和一个通常为空的字符串。如果您对元组进行排序,并使用 python 的内置排序(timesort),它应该非常快。

如果您的实数中允许使用科学记数法,请小心,例如 1e10。

如果以后有任何可能在比较中出现额外的复杂性,请使用类而不是元组。但是元组可能会更快。然后定义一个或多个比较函数(取决于您使用的是 python 2.x 还是 3.x)。

元组比较元素 0,然后是元素 1,等等。

您的类替代方案需要有cmp方法或 3.x 等效方法。

于 2012-04-24T23:03:44.010 回答
0

将字符串存储为字符串然后对其进行解析以对其进行排序似乎是错误的方法。如果你真正拥有的是

  • 主要号码
  • 次要号码
  • 可选修订

然后我强烈建议将其存储为两个整数和一个文本字段。对major_number、minor_number、revision 排序将完全按预期工作。您可以将 asnumber 定义为数据库级别的视图,也可以将其定义为基于三个基数的类以及关联的__cmp__().

于 2012-04-24T23:49:40.727 回答