根据元组中的值以不同顺序对元组列表进行排序

3

当我们想要对一个元组列表进行排序时,其中每个元组的长度为3(都是递增的),我们编写以下代码

ts = [(7, 14, 5), (3, 12, 9), (20, 22, 8), (20, 23, 24), (3, 12, 8), (4, 5, 7), (4, 5, 6), (4, 22, 17)]
ts.sort(key=lambda t: (t[0], t[1], t[2]))

这里的意思是,最开始比较的是位置0上的元素。在一个元组中,位置0上的元素越小,它就越靠近开头。如果两个元组在位置0上的值相同,那么第二个元素较小的元素将更靠近左侧。如果两个元组在第二个位置上的元素相同,则会考虑元组中的第三个元素。

所以上述代码的输出为:

Output: [(3, 12, 8), (3, 12, 9), (4, 5, 6), (4, 5, 7), (4, 22, 17), (7, 14, 5), (20, 22, 8), (20, 23, 24)]

但是如果我有时想要改变顺序(并非全部情况),例如比较第一个元素,如果一个元组的第一个元素较小,则它在排序后的列表中排在前面。但是如果第一个元素相同,则具有较大第一个元素的元组将在列表中排在前面。如果元组中的第二个元素相同,则具有较大第一个元素的元组将在列表中排在前面。

这也可以描述为:

  • 首先考虑元组中的第一个元素,按递增顺序对它们进行排序

  • 如果元组中的第一个元素相同,则按递减顺序对它们进行排序

  • 如果元组中的第二个元素相同,则按递减顺序对它们进行排序

因此,我提供的输入应该是:

Output: [(3, 12, 9), (3, 12, 8), (4, 22, 17), (4, 5, 7), (4, 5, 6), (7, 14, 5), (20, 23, 24), (20, 22, 8)]

我想知道,是否可以使用lambda函数完成此操作,或者必须有一个单独的方法来进行所需的排序。

我们也可以将这个问题推广到长度为n的元组。如果我们有一个长度为n的列表:

('increasing', 'decreasing', 'decreasing', ..., 'increasing', 'decreasing')

这意味着:
  • 首先考虑元组中的第一个元素,按递增顺序对它们进行排序

  • 如果元组中的第一个元素相同,则按递减顺序对它们进行排序

  • 如果元组中的第二个元素相同,则按递减顺序对它们进行排序

  • 如果元组中位置为n-2的元素相同,则按递增顺序排序

  • 如果元组中位置为n-1的元素相同,则按递减顺序排序

我很乐意看到关于长度为3的元组问题的解决方案,并讨论元组长度为n的泛化问题。

你的第一个例子根本不需要,元组默认按照元素顺序以递增顺序排序。 - Patrick Artner
1个回答

5

您可以更改元组值中的符号以获得期望的行为:

ts.sort(key=lambda t: (t[0], -t[1], -t[2]))

print(ts)
# [(3, 12, 9), (3, 12, 8), (4, 22, 17), (4, 5, 7), (4, 5, 6), (7, 14, 5), 
#  (20, 23, 24), (20, 22, 8)]

对于一般情况,您可以将 increasing', 'decreasing'... 列表映射为符号,并将每个元组中的 key 与符号一起使用 zip 如下:

l = ('increasing', 'decreasing', 'decreasing')
d = {'increasing':1, 'decreasing':-1}
signs = [d[i] for i in l]
ts.sort(key = lambda x: tuple(i*sign for sign,i in zip(signs, x)))

使用下面这个函数会得到与上述相同的结果:

print(ts)
# [(3, 12, 9), (3, 12, 8), (4, 22, 17), (4, 5, 7), (4, 5, 6), (7, 14, 5), 
#  (20, 23, 24), (20, 22, 8)]

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