忽略大小写对字符串列表进行排序

42

我有一个列表,其中包含表示动物名称的字符串。 我需要对列表进行排序。 如果我使用sorted(list),它将按大写字母字符串优先,然后是小写字母字符串。

但是我需要以下输出结果。

输入:

var = ['ant','bat','cat','Bat','Lion','Goat','Cat','Ant']

输出:

['ant', 'Ant', 'bat', 'Bat', 'cat', 'Cat', 'Goat', 'Lion']
3个回答

62

sort()方法和sorted()函数都带有一个关键字参数:

var.sort(key=lambda v: v.upper())

对于每个值,调用名为key的函数,并使用返回值进行排序,而不影响实际值:

>>> var=['ant','bat','cat','Bat','Lion','Goat','Cat','Ant']
>>> sorted(var, key=lambda v: v.upper())
['ant', 'Ant', 'bat', 'Bat', 'cat', 'Cat', 'Goat', 'Lion']

如果要在排序中将Ant放在ant之前,您需要在键中包含更多信息,以使值相等的情况按照给定顺序排序:

>>> sorted(var, key=lambda v: (v.upper(), v[0].islower()))
['Ant', 'ant', 'Bat', 'bat', 'Cat', 'cat', 'Goat', 'Lion']

更复杂的键生成 ('ANT', False) 用于 Ant,以及 ('ANT', True) 用于 antTrue 排在 False 之后,因此大写单词会在其小写等效词之前排序。

有关更多信息,请参见Python排序HOWTO


谢谢Martijin。有没有办法将输出也变成 ['Ant', 'ant', 'Bat', 'bat', 'Cat', 'cat', 'Goat', 'Lion']。我已经尝试了 var.sort(key=lambda v: v.lower()),但它给出了相同的输出。 - Darknight
1
@PSivachandran:你需要在键中添加一些信息,以使Antant之前排序。例如使用lambda v: (v.upper(), v[0].islower()),因为TrueFalse之后排序。 - Martijn Pieters
2
最好使用 sorted(var, key=lambda v: (v.upper(), v)) - coldfix
@coldfix:这取决于是否要求一个单词的小写版本在原词的顺序被交换后仍然出现在首字母大写的版本之前。如果是的话,返回一个元组。 - Martijn Pieters
2
当然,我认为有人想要对整个单词进行不区分大小写的排序,并对边缘情况使用第一个字母的大小写,但是突然停在那里并为其余部分使用稳定性的可能性有点太牵强了:) 如果有人编写那段代码,我可以99%肯定他们实际上想要从我的上面的评论中获取更简单的解决方案,这使得输出顺序确定,独立于它们的初始顺序的输入元素集合(因此您可以例如在 set 等上进行排序)。这既不符合key=str.upper也不符合您的最后一个建议。 - coldfix
@coldfix 还有一种可能是他们只想让大写版本先出现,这种情况下 sorted(var, key=lambda v: (v.upper(), v.swapcase())) 可能会很有效。 - Casey Kuball

27

Python 3的新答案,我想补充两点:

  1. 对于不区分大小写的比较,请使用str.casefold
  2. 直接使用方法,而不是在lambda中使用。

即:

var = ['ant','bat','cat','Bat','Lion','Goat','Cat','Ant']

var.sort(key=str.casefold)

(它可以原地排序) 现在:

>>> var
['ant', 'Ant', 'bat', 'Bat', 'cat', 'Cat', 'Goat', 'Lion']

或者,要返回一个新列表,请使用sorted

>>> var = ['ant','bat','cat','Bat','Lion','Goat','Cat','Ant']
>>> sorted(var, key=str.casefold)
['ant', 'Ant', 'bat', 'Bat', 'cat', 'Cat', 'Goat', 'Lion']

为什么这个与 str.lower 或者 str.upper 不同?根据文档:

Casefolding 类似于 lowercasing,但更加强制,因为它旨在删除字符串中所有的大小写区别。例如,德语小写字母'ß'等价于"ss"。由于它已经是小写,str.lower() 不会对 'ß' 做任何改变,而 casefold() 则将其转换为"ss"


6

我需要再添加另一个答案,因为接受的答案和更新版本缺少一个重要的东西:

这里提出的不区分大小写的排序在“相等”键的排序中不是稳定的!

这意味着: 当你有一堆混合大小写字符串要排序时,你会得到一个正确排序的列表,但是无法确定"AbC"在"aBc"之前还是之后。这甚至可能因为同一个程序的运行而有所不同。

为了始终使用稳定的默认字符串排序方式获得相同的输出,我使用以下函数:

sorted(var, key=lambda v: (v.casefold(), v))

当大小写版本没有提供排序依据时,原始密钥始终作为回退排序附加在后面。


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