【问题标题】:Python analog of PHP's natsort function (sort a list using a "natural order" algorithm) [duplicate]PHP的natsort函数的Python模拟(使用“自然顺序”算法对列表进行排序)[重复]
【发布时间】:2011-02-02 11:37:01
【问题描述】:

我想知道Python中是否有类似PHP natsort的函数?

l = ['image1.jpg', 'image15.jpg', 'image12.jpg', 'image3.jpg']
l.sort()

给予:

['image1.jpg', 'image12.jpg', 'image15.jpg', 'image3.jpg']

但我想得到:

['image1.jpg', 'image3.jpg', 'image12.jpg', 'image15.jpg']

更新

基于this link的解决方案

def try_int(s):
    "Convert to integer if possible."
    try: return int(s)
    except: return s

def natsort_key(s):
    "Used internally to get a tuple by which s is sorted."
    import re
    return map(try_int, re.findall(r'(\d+|\D+)', s))

def natcmp(a, b):
    "Natural string comparison, case sensitive."
    return cmp(natsort_key(a), natsort_key(b))

def natcasecmp(a, b):
    "Natural string comparison, ignores case."
    return natcmp(a.lower(), b.lower())

l.sort(natcasecmp);

【问题讨论】:

  • 不是内置的,不在标准库 AFAIK 中。有一个配方here,其他实现可以通过谷歌找到。
  • 您可以查看此链接:Compact python human sort
  • 这是一个自然的顺序,image3.jpg 就在它的位置

标签: python sorting natsort


【解决方案1】:

my answerNatural Sorting algorithm

import re
def natural_key(string_):
    """See https://blog.codinghorror.com/sorting-for-humans-natural-sort-order/"""
    return [int(s) if s.isdigit() else s for s in re.split(r'(\d+)', string_)]

例子:

>>> L = ['image1.jpg', 'image15.jpg', 'image12.jpg', 'image3.jpg']
>>> sorted(L)
['image1.jpg', 'image12.jpg', 'image15.jpg', 'image3.jpg']
>>> sorted(L, key=natural_key)
['image1.jpg', 'image3.jpg', 'image12.jpg', 'image15.jpg']

为了支持 Unicode 字符串,应使用 .isdecimal() 代替 .isdigit()。请参阅@phihag's comment 中的示例。相关:How to reveal Unicodes numeric value property

.isdigit() 也可能在某些语言环境(例如 '\xb2' ('²') in cp1252 locale on Windows)中对 Python 2 上的字节串失败(返回值不被 int() 接受)。

【讨论】:

  • @phihag:它适用于 Python 3。
  • 哎呀,你完全正确。我搞砸了测试用例——错误与 Python 3 无关。\disdigit 只是匹配 int 不接受的值。 Observe [u'²'].sort(key=natural_key).
  • 警告:适用于所示的特定示例,但对于 ['elm1', 'Elm2'] 和 ['0.501', '0.55'] 和 [0.01, 0.1, 1] 等情况失败.. . 请参阅stackoverflow.com/questions/4836710/… for lower() 和我对 Python 自然排序顺序的更通用解决方案。
  • @ScottLawton:它按预期工作。可以对“自然排序”使用不同的定义。不能说其他(广泛使用的)定义是错误的。
  • 我可以继续问,如果我的数组是像[['image1.jpg', 'pathToImage1'], ['image15.jpg', 'pathToImage15'], ['image12.jpg', 'pathToImage12'], ['image3.jpg', 'pathToImage3']] 这样的二维数组,并且我希望它以相同的方式排序(按数值或每个子的第一个元素排序数组,返回[['image1.jpg', 'pathToImage1'], ['image3.jpg', 'pathToImage3'], ['image12.jpg', 'pathToImage12'], ['image15.jpg', 'pathToImage15']]),我应该在哪里调整此代码才能工作?谢谢! (我需要为这个问题开一个新帖子吗?)
【解决方案2】:

此函数可用作 Python 2.x 和 3.x 中 sortedkey= 参数:

def sortkey_natural(s):
    return tuple(int(part) if re.match(r'[0-9]+$', part) else part
                for part in re.split(r'([0-9]+)', s))

【讨论】:

  • .isdecimal() 是唯一的 unicode 方法。它不适用于字节串。 .isdecimal() 匹配与 \d 相同的字符集 ([Nd]),在 Unicode 情况下大于 [0-9]
  • 我不知道排序两个字节字符串的语义是什么,所以我没有考虑。但你是对的,测试是错误的。切换到re.match
  • +1。你不使用 proper Unicode sorting 所以我不明白你为什么会拒绝字节串。顺便说一句,在 *nix 上,文件名只是字节。您不希望 ls 仅仅因为目录中有一个有趣的文件名而中断。
【解决方案3】:

您可以在 PyPI 上查看第三方 natsort 库:

>>> import natsort
>>> l = ['image1.jpg', 'image15.jpg', 'image12.jpg', 'image3.jpg']
>>> natsort.natsorted(l)
['image1.jpg', 'image3.jpg', 'image12.jpg', 'image15.jpg']

完全公开,我是作者。

【讨论】:

  • 我想用,但是python 3.5没找到
  • @FiReTiTi 它与python 2和python 3都兼容。我很好奇你是怎么断定它不适用于python 3的。
  • 我尝试使用它,但 natsort 不可用。所以我让 MacPort 安装它,但它想强制我安装 python 3.4 或 2.7 以及 natsort,我不想要,因为已经安装了 python 3.5。
  • @FiReTiTi 这听起来像是向 MacPort 人员报告的事情。 natsort 适用于所有现代版本的 python。您可以使用 pip,或者如果您使用的是 Mac,我会考虑更改为 Homebrew。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-08-02
  • 2018-02-19
  • 1970-01-01
  • 1970-01-01
  • 2021-12-23
  • 2012-12-21
  • 2019-12-20
相关资源
最近更新 更多