如何对字符串列表进行数字排序

197
我知道这听起来很琐碎,但我没有意识到Python的sort()函数有点奇怪。我有一个由实际上是字符串形式的"数字"组成的列表,所以我首先将它们转换为整数,然后尝试进行排序。
list1=["1","10","3","22","23","4","2","200"]
for item in list1:
    item=int(item)

list1.sort()
print list1

给我:
['1', '10', '2', '200', '22', '23', '3', '4']

我想要。
['1','2','3','4','10','22','23','200']

我找了一些与排序数字集相关的算法,但我找到的都是涉及排序字母数字集的。
我知道这可能是一个简单的问题,但谷歌和我的教科书都没有提供比.sort()函数更有用或不那么有用的东西。

14
请注意,你的 for 循环并没有执行你所认为的操作。 - deinst
1
你从未更新过 list1,是什么让你认为 list 被更新了? - S.Lott
当输入list1 = ['1', '1.10', '1.11', '1.1', '1.2']时,会出现类似的问题。我期望得到的输出是['1', '1.1', '1.2', '1.10', '1.11'],但实际上得到的却是['1', '1.1', '1.10', '1.11', '1.2']。 - sathish
2
在Python 3中,您可能希望使用sorted(mylist) - Akin Hwan
相关:*将一组数字字符串按升序排序* - Peter Mortensen
14个回答

230

你实际上没有将字符串转换成整数。或者说,你确实转换了,但是你没有对结果做任何处理。你需要的是:

list1 = ["1","10","3","22","23","4","2","200"]
list1 = [int(x) for x in list1]
list1.sort()

如果由于某些原因你需要保留字符串而不是整数(通常是一个坏主意,但也许你需要保留前导零或其他东西),你可以使用 key 函数。 sort 接受一个名为 key 的参数,它是在比较每个元素之前调用的函数。键函数的返回值将被比较,而不是直接比较列表元素:

list1 = ["1","10","3","22","23","4","2","200"]
# call int(x) on each element before comparing it
list1.sort(key=int)
# or if you want to do it all in the same line
list1 = sorted([int(x) for x in list1]) 

8
当我在 Python 2.7 中尝试使用 key=int 时,返回值为 None。 - KI4JGT
1
如果列表元素存储为“整数”,则此方法有效,但如果是浮点数值该如何处理?例如,list1 = [1, 1.10, 1.11, 1.1, 1.2]。 - sathish
3
sort方法会修改列表并返回空值。因此,不要使用list1 = list1.sort(key=int),而是直接使用list1.sort(key=int)即可对list1进行排序。 - Josiah Yoder
4
@KI4JGT .sort() 是一个原地操作符,它返回 None,它对列表进行排序,你可能想使用 sorted()。 - sherpya

88

昨天我遇到了同样的问题,发现一个名为 natsort 的模块可以解决你的问题。使用方法:

from natsort import natsorted # pip install natsort

# Example list of strings
a = ['1', '10', '2', '3', '11']

[In]  sorted(a)
[Out] ['1', '10', '11', '2', '3']

[In]  natsorted(a)
[Out] ['1', '2', '3', '10', '11']

# Your array may contain strings
[In]  natsorted(['string11', 'string3', 'string1', 'string10', 'string100'])
[Out] ['string1', 'string3', 'string10', 'string11', 'string100']

它也可以作为字典的等价物来使用 sorted


谢谢!正是我想要的!对于排序包含版本号的字符串非常有帮助,比如说。 - Alexander Samoylov

44
你可以将函数传递给key参数以使用.sort方法。这样,系统将按照key(x)而不是x进行排序。
list1.sort(key=int)

顺便提一句,如果要永久将列表转换为整数,请使用map函数

list1 = list(map(int, list1))   # you don't need to call list() in Python 2.x

或者列表推导式
list1 = [int(x) for x in list1]

list1.sort(key=int) 在原地排序,同时不改变列表内容,非常好! - abdelgha4

33

如果您想使用 sorted() 函数: sorted(list1, key=int)

它会返回一个新的排序好的列表。


2
也适用于集合! - M T

21

您也可以使用:

import re

def sort_human(l):
    convert = lambda text: float(text) if text.isdigit() else text
    alphanum = lambda key: [convert(c) for c in re.split('([-+]?[0-9]*\.?[0-9]*)', key)]
    l.sort(key=alphanum)
    return l

这与您在互联网上找到的其他资料非常相似,但也适用于像 [abc0.1、abc0.2、...] 这样的字母数字。


你可能应该返回一个新的列表或修改列表,而不是两者都做。以上代码修改了列表然后将其返回。可以使用 sorted() 来创建一个新列表。 - Victor Nordam Suadicani
2
不幸的是,这仅适用于字母和数字未按相同顺序出现的情况;例如 ["abc123", "123abc"]TypeError: '<' not supported between instances of 'float' and 'str'。解决方案:使用 (float(text), "") if text.isdigit() else (float("inf"), text) 替换 covert 函数。它将始终返回一个 (float, str) 元组,因此比较将始终有效。 - Claude
在我的清单上,不知何故,这段代码没有起作用,但这段代码却起作用了: alphanum = lambda key: [float(c) for c in re.findall('([+-]?\d+\.?\d*)', key)] - undefined

14

Python的排序并不奇怪。只是这段代码:

for item in list1:
   item=int(item)

它并没有做你想象中的事情 - item并没有被替换回列表中,而是被丢弃了。

无论如何,正确的解决方案是使用key=int,就像其他人已经向你展示的那样。


9

Seamus Campbell的回答在Python 2.x上不起作用。

list1 = sorted(list1, key=lambda e: int(e))使用lambda函数效果很好。


3
试试这个。它会按降序原地对列表进行排序(在这种情况下不需要指定键)。
过程
listB = [24, 13, -15, -36, 8, 22, 48, 25, 46, -9]
listC = sorted(listB, reverse=True) # listB remains untouched
print listC

输出:

 [48, 46, 25, 24, 22, 13, 8, -9, -15, -36]

2
真正的问题是'sort'按字母数字顺序对事物进行排序。
所以,如果你有一个列表,['1', '2', '10', '19'],然后运行'sort',你会得到['1', '10', '19', '2']。也就是说,10在2之前,因为它从第一个字符开始查看并进行排序。
似乎Python中的大多数方法都以这种顺序返回结果。例如,如果你有一个名为'abc'的目录,其中文件标记为1.jpg、2.jpg等,一直到15.jpg,然后你执行file_list=os.listdir(abc),file_list的顺序不是你期望的顺序,而是file_list=['1.jpg', '11.jpg'---'15.jpg', '2.jpg]。
如果文件处理的顺序很重要(这可能是你按数字命名的原因),那么实际的顺序可能不是你想象中的。你可以通过使用“零”填充来避免这个问题。例如,如果你有一个列表,alist=['01', '03', '05', '10', '02','04', '06'],并对其运行'sort',你会得到你想要的顺序,alist=['01', '02', 等等],因为第一个字符是0,它在1之前。所需的零填充数量取决于列表中最大的值。
举个例子,如果最大值在100和1000之间,你需要将单个数字填充为001、002 --- 010、011 -- 100、101等。

1
最新的解决方案是正确的。你正在将解决方案作为字符串进行读取,这种情况下顺序是1,然后是100,然后是104,接着是2,然后是21,然后是2001001010,以此类推。
你必须将输入强制转换为整数:
排序后的字符串:
stringList = (1, 10, 2, 21, 3)
排序后的整数:
intList = (1, 2, 3, 10, 21)
要进行强制转换,只需将stringList放在int(blahblah)中即可。
再次强调:
stringList = (1, 10, 2, 21, 3)

newList = int (stringList)

print newList

=> returns (1, 2, 3, 10, 21)

1
类型错误:int()的参数必须是字符串或数字,而不是元组。 - Cees Timmerman
此外,您的stringList中的字符串应该有引号。 - Teepeemm
3
这是一个相当大胆的预测:“最近的解决方案是正确的” ;) - GreenAsJade
关于“最新的解决方案是正确的”:这样的相对引用并不可靠(或稳定)。它指的是哪个答案? - Peter Mortensen
好的,OP已经离开了:「最后一次出现在9年前」 - Peter Mortensen
“Most recent”可能并不是字面上的意思,而是指在默认排序顺序下时间最近的答案,很可能是Daniel Roseman的回答。尽管不太清楚具体指的是哪个答案。 - Peter Mortensen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接