按特定元素和该元素的子字符串对元组列表进行排序

时间:2018-12-08 02:53:53

标签: python sorting lambda tuples

我正在尝试对元组列表进行排序。它们的格式如下:

("First Last", 3, 0)

或者换句话说:

(string, int, int)

我想按字符串值(第一个元组元素)排序。我发现了如何从以下令人敬畏的答案中按某个元素对元组列表进行排序:https://stackoverflow.com/a/3121985/8887398

这是我的代码:

# Yes, I do want to start from element 1 btw
myList[1:].sort(key=lambda tup: tup[0])

当我只有名字作为元组中字符串的值时,这非常有用,例如:

("George", 8, 3)

然后我添加了姓氏,例如:

("George Manning", 8, 3)

它不再正确排序,所以我尝试了这一点:

myList[1:].sort(key=lambda tup: (tup[0].split(" ")[1]))

我非常有信心这会起作用。没有。我感到困惑,因为我知道我的split方法正确地从调试中提取了姓氏。我究竟做错了什么?如何按姓氏对列表进行排序?

这是一个例子。是的,他们是假名字:

myList = [
    ("NAME", "SOME LABEL 1", "SOME LABEL 2"),
    ("Kevin Lee", 45, 4),
    ("John Bowes", 35, 2),
    ("George Smith", 8, 3),
    ("Gina Marnico", 40, 3),
    ("Alice Gordon", 48, 7),
    ("Lee Jackson", 49, 7),
    ("Adam Hao", 50, 4),
    ("Adrian Benco", 23, 2),
    ("Jessica Farner", 43, 20),
    ("Greg Hyde", 34, 20),
    ("Ryan Valins", 39, 7),
    ("Gary Funa", 49, 7),
    ("Sam Tuno", 15, 4),
    ("Katy Sendej", 30, 2),
    ("Jessica Randolf", 44, 8),
    ("Gina Gundo", 47, 30)
]

myList[1:].sort(key=lambda tup: (tup[0].split(" ")[1]))

我跳过第一个值,因为它是标签信息。我希望该元素保持不变,并且列表的其余部分按姓氏排序。

4 个答案:

答案 0 :(得分:2)

如果您想按姓氏进行排序,这是一件辛劳的工作:

Optional

结果:

a = myList[1:]
a.sort(key=lambda tup: tup[0].split(" ")[1])
myList[1:] = a

如果要按姓氏进行排序,则首先可以执行以下操作:

[
    ('NAME', 'SOME LABEL 1', 'SOME LABEL 2'),
    ('Adrian Benco', 23, 2),
    ('John Bowes', 35, 2),
    ('Jessica Farner', 43, 20),
    ('Gary Funa', 49, 7),
    ('Alice Gordon', 48, 7),
    ('Gina Gundo', 47, 30),
    ('Adam Hao', 50, 4),
    ('Greg Hyde', 34, 20),
    ('Lee Jackson', 49, 7),
    ('Kevin Lee', 45, 4),
    ('Gina Marnico', 40, 3),
    ('Jessica Randolf', 44, 8),
    ('Katy Sendej', 30, 2),
    ('George Smith', 8, 3),
    ('Sam Tuno', 15, 4),
    ('Ryan Valins', 39, 7)
]

答案 1 :(得分:0)

删除标签行即可:

    myList.sort(key=lambda tup: (tup[0].split(" ")[1]))

结果:

    ('Adrian Benco', 23, 2) 
    ('John Bowes', 35, 2) 
    ('Jessica Farner', 43, 20) 
    ('Gary Funa', 49, 7) 
    ('Alice Gordon', 48, 7) 
    ('Gina Gundo', 47, 30) 
    ('Adam Hao', 50, 4)
    ('Greg Hyde', 34, 20) 
    ('Lee Jackson', 49, 7) 
    ('Kevin Lee', 45, 4)
    ('Gina Marnico', 40, 3)
    ('Jessica Randolf', 44, 8) 
    ('Katy Sendej', 30, 2) 
    ('George Smith', 8, 3) 
    ('Sam Tuno', 15, 4) 
    ('Ryan Valins', 39, 7)

答案 2 :(得分:0)

[myList[0]] + sorted(myList[1:], key=lambda t: t[0].split(' ')[1])

您还可以选择不进行适当排序并保持标签线不变。

答案 3 :(得分:0)

表达式myList[1:]创建一个单独的列表对象,其缓冲区与myList的缓冲区不同。您已成功就地对该对象进行了排序,但是结果被丢弃而不会影响原始的myList

您有两种选择。最直接的方法就是保留排序后的对象,然后重新插入它,或者只是将其固定在第一个元素上:

data = myList[1:]
data.sort(key=lambda x: x[0].split()[::-1])
myList[1:] = data

...
myList = [myList[0]] + data

...
myList = myList[:1] + data

使用sorted,可以使代码更加简洁,因为它具有返回值:

myList[1:] = sorted(myList[1:], key=lambda x: x[0].split()[::-1]))

myList = [myList[0]] + sorted(myList[1:], key=lambda x: x[0].split()[::-1]))

myList = myList[:1] + sorted(myList[1:], key=lambda x: x[0].split()[::-1]))

您甚至可以在此处使用wrap-sort-unwrap模式。包装器将是一个标志,指示元素是否为标头,使您可以立即对整个列表进行排序,并将标头保持在原位置。我不建议在此使用此方法,因为它比其他方法过于刻板且难以理解。但是,您可能会发现该模式在其他地方很有用:

myList = [x[1] for x in sorted(enumerate(myList), key=lambda x: (bool(x[0]), x[1][0].split()[::-1]))]

如果您更改程序的设计以将同类数据保留在列表中,则所有这些问题都将消失。假设您从CSV文件中获取列表。您始终可以执行以下操作:

myHeader, *myList = myList
myList.sort(...)

第一行是一种简单的语法糖,用于剥离第一个元素并重新包装其余元素。它基本上等同于

myHeader, myList = myList[0], myList[1:]

在所有情况下,我建议在密钥中使用.split()[::-1]或至少使用.split()[-1],而不要使用.split(' ')[1]。如果姓氏匹配,则第一个选项将允许您按名字排序。它依赖于词典的序列比较。第二个选项将使用名称的最后一个元素作为排序键,使其对中间名称和单个名称具有鲁棒性。

相关问题