按自然顺序排序字符串列表

6

我有以下内容:

sorted( ("A","a","b","B","CC","c"), key=lambda x: x.lower() )

这将会得到:

['A', 'a', 'b', 'B', 'c', 'CC']

我该如何进行这样的排序:

['a', 'A', 'b', 'B', 'c', 'CC']

如果有两个相同的值,则较小的值排在前面——a优先于A。

我猜我需要这样做:

sorted( ("A","a","b","B","CC","c"), key=lambda x: (x.lower(),x) )

但这会先显示 A 再显示 a:
['A', 'a', 'B', 'b', 'c', 'CC']

我该如何做相反的操作?

更新

为了进一步澄清,以下字符串:["A","a","aA","aa"] 应按以下方式排序:

["a","A","aa","aA"]

因此,“aa”在“aA”之前,“aaA”在“aAa”之前,以此类推。
因此:
lst = ["A","aA","aa","aaa","aAa","aaA","b","B","CC","c"]

应该排序为:

['A', 'aa', 'aA', 'aaa', 'aaA', 'aAa', 'b', 'B', 'c', 'CC']

1
其他人已经提供了解决方案,我只想补充一点:Python的sorted是稳定排序算法:如果多个记录具有相同的键(如您的情况中的aA),它们的原始顺序将被保留。 - Daweo
4个回答

9
您可以这样做:
lst = ["A","a","b","B","CC","c"]

result = sorted(lst, key= lambda x: (x.lower(), not x.islower()))
print(result)

输出

['a', 'A', 'b', 'B', 'c', 'CC']

更新

根据您提供的新示例,您可以使用以下密钥:

lst = ["A", "aA", "aa", "aaa", "aAa", "aaA", "b", "B", "CC", "c"]
result = sorted(lst, key=lambda x: (x.lower(), ''.join(str(c.isupper()) for c in x)))
print(result)

输出

['A', 'aa', 'aA', 'aaa', 'aaA', 'aAa', 'b', 'B', 'c', 'CC']

对于另一个例子(["A","a","aA","aa"]),它给出:
['a', 'A', 'aa', 'aA']

由于我的问题没有完全说明我想要做什么,因此更新了我的问题。 - Baz
@Baz 更新了答案! - Dani Mesejo

5

这是一种方法:

sorted( lst, key=lambda x: (x.lower(), *map(str.isupper, x)) )
#['A', 'aa', 'aA', 'aaa', 'aaA', 'aAa', 'b', 'B', 'c', 'CC']

首先按不区分大小写的字母进行排序。然后将每个字符串的所有字符调用str.upper作为第二个排序条件。这将使相同长度的字符串中小写字母排在前面。

Python 2版本

上述语法仅适用于python3,但您可以在python2中等效地执行以下操作:

sorted( lst, key=lambda x: ((x.lower(),) + tuple(map(str.isupper, x))) )

由于我的问题没有完全表述清楚,所以我更新了它,以便更明确我想要做的事情。 - Baz
@Baz说得有道理。这是一个简单的更改-已修复。 - pault

0
你可以这样做:
>>> sorted( ("A","a","b","B","CC","c"), key=lambda x: (x.lower() + str(x != x.lower()) ,x) )
['a', 'A', 'b', 'B', 'c', 'CC']

它的工作原理是将字母的小写版本与实际字母进行比较。如果小写匹配,则str(x != x.lower()将为0,否则为1


0

这里有一个基于之前答案的可行解决方案:

sorted(lst, key= lambda x: (x.lower(), [c.isupper() for c in x]))

而且这个似乎也能工作:

sorted(lst, key= lambda x: (x.lower(), x.swapcase()))

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