2011-10-17 34 views
2

我有一个可以表示整数以及名称的字符串列表。 默认字符串比较执行以下操作:以下列方式对字符串列表进行排序的最简单方法是什么?

sorted(['1','2','3','4','10','102','14','Alice','John','Sally']) 
['1', '10', '102', '14', '2', '3', '4', 'Alice', 'John', 'Sally'] 

我想如下对列表进行排序:

['1', '2', '3', '4', '10', '14', '102', 'Alice', 'John', 'Sally'] 

这意味着:

  1. 排序所有这些数字代表一个整数串
  2. 按字母顺序排列“真实”字符串,并将此列表附加到(1.)

我尝试过使用比较方法,但我不知道如何确定干净如果字符串表示一个整数没有尝试/除外?

在此先感谢

回答

10

如果没有负数:

lyst = ['1','2','3','4','10','102','14','Alice','John','Sally'] 
print sorted(lyst, key=lambda k: int(k) if k.isdigit() else k) 

下面是一个不依赖于CPython的详细信息,并与Python 3兼容版本:

sorted(lyst, key=lambda k: (0, int(k)) if k.isdigit() else (1, k)) 

这里关键是一个元组。对于数字或文本,元组中的第一项是0或1,这会导致数字在文本之前排序。然后,元组中的第二项是值,这会使值在其组中正确排序。我最初使用float("+inf")来使文本项在数字之后进行排序,但这种方法(受Tom Zych的答案启发)更简单快捷。

如果你想在字符串排序不区分大小写,只需添加.lower()

sorted(lyst, key=lambda k: (0, int(k)) if k.isdigit() else (1, k.lower())) 
+0

谢谢,正是我需要的! (在我的情况下没有负数的发生) – any1

+4

请注意:(1)依赖于CPtyhon的实现细节(ints比较字符串之前而不是之后); (2)不适用于Python 3,因为不允许将字符串与字符串进行比较。 – NPE

+0

好点,增加了另一个版本。 – kindall

5

以下工作在两个的Python 2和Python 3:

l = ['1','2','3','4','10','102','14','Alice','John','Sally','33'] 
num, alpha = [], [] 
[num.append(elem) if elem.isdigit() else alpha.append(elem) for elem in l] 
result = sorted(num, key=int) + sorted(alpha) 
print(result) 

它避免了比较字符串通过划分列表来整合。避免这种比较的原因是它要么是not fully specified(Python 2)要么是禁止的(Python 3)。

+0

+1。我喜欢这可以在2和3上工作。我不喜欢使用布尔值的下标,因为这很容易避免。如果elem.isdigit()else ele.append(elem)for elem in l]',我会将list comp更改为'[num.append(elem)。它也允许你剪切一行。 –

+0

@StevenRumbalski:很好的建议,谢谢。 – NPE

+0

聪明,upvote。你可以避免在'any(...)'中使用列表理解来创建'None'列表。 – kindall

5

这应该与sort采取关键功能的版本一起使用。

def sortkey(s): 
    try: 
     n = int(s) 
     return (0, n) 
    except ValueError: 
     return (1, s) 
+0

这是可行的,因为元组按照字典顺序进行比较;第一项是比较;如果它们是相同的,则比较第二项,等等。非常好。 –

+0

为了使这个工作适用于Python 3,返回整数的'(0,n,“”)'和字符串的'(1,0,s)'。我喜欢这也适用于负数。但是,它可以产生不正确的浮标结果。 –

+0

@StevenRumbalski:OP确实说过“整数”。如果有浮标,当然,我们需要为它们添加一个试验转换。我的代码看起来像3.1中写的那样正常工作;你为什么认为你的改变是必要的? –

0

我会去的比较功能:

import types 

def cmp_func(val1, val2): 
    # is val1 an integer? 
    try: 
    val1 = int(val1) 
    except ValueError: 
    pass # val1 is no integer 
    try: 
    val2 = int(val2) 
    except ValueError: 
    pass #val2 is no integer 

    if type(val1) == types.IntType and type(val2) == types.IntType: 
    return cmp(val1, val2) 
    elif type(val1) == types.StringType and type(val2) == types.IntType: 
    # firstly strings, afterwards integer values 
    return -1 
    elif type(val1) == types.IntType and type(val2) == types.StringType: 
    # firstly strings, afterwards integer values 
    return 1 
    else: 
    return cmp(val1, val2) 


if __name__ == "__main__": 
    my_list = ['1', '10', '102', '14', '2', '3', '4', 'Alice', 'John', 'Sally'] 
    my_list.sort(cmp_func) 
    print(my_list) 
相关问题