在Python中,通过元组的第一个元素对包含字母和数字的元组列表进行自然排序。

4

一道之前的stackoverflow问题解释了如何按字母数字顺序排序字符串列表。我想通过元组的第一个元素将元组列表按字母数字顺序排序。

示例1:

>>> sort_naturally_tuple([('b', 0), ('0', 1), ('a', 2)])
[('0', 1), ('a', 2), ('b', 0)]

例子2:

>>> sort_naturally_tuple([('b10', 0), ('0', 1), ('b9', 2)])
[('0', 1), ('b9', 2), ('b10', 0)]

更新: 为了强调字母数字因素,请查看示例2。


1
它的拼写是 sorted(),并且与那个函数完全相同(除了它返回一个生成器而不是列表)。 - Kirk Strauser
@Kirk sorted 无论输入是迭代器、元组或生成器表达式,都会返回一个列表。 - JBernardo
@JBernardo 你当然是对的。我当时在想“reversed”,所以在核实之前就这样写了。如果我让任何人感到困惑,我向他们道歉。 - Kirk Strauser
4个回答

5

使用其他问题的第二个答案,一般化以支持任何作为获取键基础的项目方法:

import re
from operator import itemgetter

def sorted_nicely(l, key):
    """ Sort the given iterable in the way that humans expect."""
    convert = lambda text: int(text) if text.isdigit() else text
    alphanum_key = lambda item: [ convert(c) for c in re.split('([0-9]+)', key(item)) ]
    return sorted(l, key = alphanum_key)


print sorted_nicely([('b10', 0), ('0', 1), ('b9', 2)], itemgetter(0))

这与那个答案完全相同,只是泛化为使用任何可调用对象作为对项的操作。如果您只想在字符串上执行此操作,可以使用lambda item: item;如果您想在列表、元组、字典或集合上执行此操作,可以使用operator.itemgetter(key_or_index_you_want);如果您想在类实例上执行此操作,则可以使用operator.attrgetter('attribute_name_you_want')
它会返回:
[('0', 1), ('b9', 2), ('b10', 0)]

针对你的第二个例子。


当然,只需将 key[0] 更改为 key['您想排序的键'] - agf
简单!那再进一步,能否让 sorted_nicely() 方法根据你想排序的内容进行排序?例如,sorted_nicely(l, 'key[0]') 将按 l 中的第一个元素进行排序。另一个例子是 sorted_nicely(d, 'key[\'the_key_you_want_to_sort_by\')' 将通过元素 d['the_key_you_want_to_sort_by'] 对字典 d 进行排序。 - paragbaxi
这太完美了。现在我可以用它来处理字典、列表和元组! - paragbaxi

4

元组默认按其元素排序,从第一个元素开始。因此只需执行以下操作

L = [('b', 0), ('0', 1), ('a', 2)]
L.sort()
print L
# or create a new, sorted list
print sorted([('b', 0), ('0', 1), ('a', 2)])

您提到的问题涉及自然排序,与通常(字母数字)排序不同。

假设您只想对第一个项目进行自然排序:

import re
def naturalize(item):
    # turn 'b10' into ('b',10) which sorts correctly
    m = re.match(r'(\w+?)(\d+)', item)
    return m.groups()
# now sort by using this function on the first element of the tuple:
print sorted(L, key=lambda tup: naturalize(tup[0]))

谢谢。非常抱歉,我没有强调自然排序。sorted([('b10', 0), ('0', 1), ('b9', 2)]) 返回 [('0', 1), ('b10', 0), ('b9', 2)],这是不正确的,因为 ('b9', 2) 应该在 ('b10', 0) 之前。 - paragbaxi

1

正如其他人所指出的那样,sorted默认使用元组的第一个元素。如果您希望修改此默认行为,可以指定在比较过程中使用的键。

sorted([('b', 0), ('0', 1), ('a', 2)])

将返回与以下内容相同:

sorted([('b', 0), ('0', 1), ('a', 2)], key=lambda item: item[0])

如果想要按第二个元素排序,请尝试以下代码:

sorted([('b', 0), ('0', 1), ('a', 2)], key=lambda item: item[1])

4
使用 operator.itemgetter 方法,而不是 lambda 表达式。 - agf
不知道这个。所以类似于sorted(arr,key=itemgetter(1)(arr))按第二个元素排序吗?顺便说一下,谢谢。 - sampwing
谢谢。很抱歉,我没有强调自然排序。sorted([('b10', 0), ('0', 1), ('b9', 2)])返回[('0', 1), ('b10', 0), ('b9', 2)],这是不正确的,因为('b9', 2)应该在('b10', 0)之前。 - paragbaxi
from operator import itemgetter; sorted([('b', 0), ('0', 1), ('a', 2)], key=itemgetter(1)) - agf
sorted([('b10', 0), ('0', 1), ('b9', 2)], key=lambda item: item[0]) 返回 [('0', 1), ('b10', 0), ('b9', 2)],这是不正确的,因为 ('b9', 2) 应该在 ('b10', 0) 之前。 - paragbaxi

0

natsort 模块默认情况下可以轻松实现此功能,无需额外操作

>>> from natsort import natsorted
>>> natsorted([('b', 0), ('0', 1), ('a', 2)])
[('0', 1), ('a', 2), ('b', 0)]
>>> natsorted([('b10', 0), ('0', 1), ('b9', 2)])
[('0', 1), ('b9', 2), ('b10', 0)]

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