python中对字符串字母排序_在Python中,我如何自然地对字母数字字符串列表进行排序,以使字母字符排在数字字符之前?...

This is a fun little challenge that confronted me recently. I'll provide my answer below, but I'm curious to see whether there are more elegant or efficient solutions.

A delineation of the requirements as they were presented to me:

Strings are alphanumeric (see test dataset below)

Strings should be sorted naturally (see this question for explanation)

Alpha characters should be sorted ahead of numeric characters (i.e. 'abc' before '100')

Uppercase instances of alpha chars should be sorted ahead of lowercase instances (i.e. 'ABc', 'Abc', 'abc')

Here's a test dataset:

test_cases = [

# (unsorted list, sorted list)

(list('bca'), ['a', 'b', 'c']),

(list('CbA'), ['A', 'b', 'C']),

(list('r0B9a'), ['a', 'B', 'r', '0', '9']),

(['a2', '1a', '10a', 'a1', 'a100'], ['a1', 'a2', 'a100', '1a', '10a']),

(['GAM', 'alp2', 'ALP11', '1', 'alp100', 'alp10', '100', 'alp1', '2'],

['alp1', 'alp2', 'alp10', 'ALP11', 'alp100', 'GAM', '1', '2', '100']),

(list('ra0b9A'), ['A', 'a', 'b', 'r', '0', '9']),

(['Abc', 'abc', 'ABc'], ['ABc', 'Abc', 'abc']),

]

Bonus Test Case

This is inspired by Janne Karila's comment below that the selected answer currently fails (but wouldn't really be a practical concern in my case):

(['0A', '00a', 'a', 'A', 'A0', '00A', '0', 'a0', '00', '0a'],

['A', 'a', 'A0', 'a0', '0', '00', '0A', '00A', '0a', '00a'])

解决方案re_natural = re.compile('[0-9]+|[^0-9]+')

def natural_key(s):

return [(1, int(c)) if c.isdigit() else (0, c.lower()) for c in re_natural.findall(s)] + [s]

for case in test_cases:

print case[1]

print sorted(case[0], key=natural_key)

['a', 'b', 'c']

['a', 'b', 'c']

['A', 'b', 'C']

['A', 'b', 'C']

['a', 'B', 'r', '0', '9']

['a', 'B', 'r', '0', '9']

['a1', 'a2', 'a100', '1a', '10a']

['a1', 'a2', 'a100', '1a', '10a']

['alp1', 'alp2', 'alp10', 'ALP11', 'alp100', 'GAM', '1', '2', '100']

['alp1', 'alp2', 'alp10', 'ALP11', 'alp100', 'GAM', '1', '2', '100']

['A', 'a', 'b', 'r', '0', '9']

['A', 'a', 'b', 'r', '0', '9']

['ABc', 'Abc', 'abc']

['ABc', 'Abc', 'abc']

Edit: I decided to revisit this question and see if it would be possible to handle the bonus case. It requires being more sophisticated in the tie-breaker portion of the key. To match the desired results, the alpha parts of the key must be considered before the numeric parts. I also added a marker between the natural section of the key and the tie-breaker so that short keys always come before long ones.

def natural_key2(s):

parts = re_natural.findall(s)

natural = [(1, int(c)) if c.isdigit() else (0, c.lower()) for c in parts]

ties_alpha = [c for c in parts if not c.isdigit()]

ties_numeric = [c for c in parts if c.isdigit()]

return natural + [(-1,)] + ties_alpha + ties_numeric

This generates identical results for the test cases above, plus the desired output for the bonus case:

['A', 'a', 'A0', 'a0', '0', '00', '0A', '00A', '0a', '00a']

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值