我希望先按编号,然后按案文对以下清单进行排序。
lst = ['b-3', 'a-2', 'c-4', 'd-2']
# result:
# ['a-2', 'd-2', 'b-3', 'c-4']尝试1
res = sorted(lst, key=lambda x: (int(x.split('-')[1]), x.split('-')[0]))我对此并不满意,因为它需要分割一个字符串两次,以提取相关组件。
尝试2
我想出了下面的解决方案。但我希望通过Pythonic lambda语句有一个更简洁的解决方案。
def sorter_func(x):
text, num = x.split('-')
return int(num), text
res = sorted(lst, key=sorter_func)我看了理解python中的嵌套lambda函数行为,但无法直接适应这个解决方案。有没有一种更简洁的方法来重写上面的代码?
发布于 2018-07-06 21:21:41
在几乎所有的情况下,我都会同意你的第二次尝试。它具有可读性和简洁性(每次我更喜欢三行简单的行,而不是一行复杂的行!)--尽管函数名可能更具有描述性。但是如果你用它作为局部函数,那就不重要了。
您还必须记住,Python使用的是key函数,而不是cmp (比较)函数。因此,要对可迭代的长度n进行排序,key函数被调用为精确的n时间,但是排序通常会进行O(n * log(n))比较。因此,每当您的密钥函数具有O(1)算法复杂性时,键函数调用开销就不会有多大影响。那是因为
O(n*log(n)) + O(n) == O(n*log(n))有一个例外,这是Pythons sort最好的情况:在最好的情况下,sort只进行O(n)比较,但只有在迭代已经排序(或几乎排序)的情况下才会发生。如果Python有一个比较函数(在Python2中确实有一个),那么函数的常量因素就会更重要,因为它将被称为O(n * log(n))时间(每次比较调用一次)。
所以,不要为了更简洁或者让它更快而烦恼(除非你可以在不引入太大的常数因素的情况下减少大的O,那么你应该去做!),首先要考虑的应该是可读性。因此,您应该真正地,而不是,做任何嵌套的lambda或任何其他花哨的构造(除了作为练习)。
长话短说,只需使用你的第二个:
def sorter_func(x):
text, num = x.split('-')
return int(num), text
res = sorted(lst, key=sorter_func)顺便说一句,也是所有提议的方法中最快的(尽管差别不大):

摘要:它是可读的和快速的!
复制基准测试的代码。它需要安装simple_benchmark才能使其工作(免责声明:这是我自己的库),但是可能有类似的框架来完成这类任务,但我只是熟悉它:
# My specs: Windows 10, Python 3.6.6 (conda)
import toolz
import iteration_utilities as it
def approach_jpp_1(lst):
return sorted(lst, key=lambda x: (int(x.split('-')[1]), x.split('-')[0]))
def approach_jpp_2(lst):
def sorter_func(x):
text, num = x.split('-')
return int(num), text
return sorted(lst, key=sorter_func)
def jpp_nested_lambda(lst):
return sorted(lst, key=lambda x: (lambda y: (int(y[1]), y[0]))(x.split('-')))
def toolz_compose(lst):
return sorted(lst, key=toolz.compose(lambda x: (int(x[1]), x[0]), lambda x: x.split('-')))
def AshwiniChaudhary_list_comprehension(lst):
return sorted(lst, key=lambda x: [(int(num), text) for text, num in [x.split('-')]])
def AshwiniChaudhary_next(lst):
return sorted(lst, key=lambda x: next((int(num), text) for text, num in [x.split('-')]))
def PaulCornelius(lst):
return sorted(lst, key=lambda x: tuple(f(a) for f, a in zip((int, str), reversed(x.split('-')))))
def JeanFrançoisFabre(lst):
return sorted(lst, key=lambda s : [x if i else int(x) for i,x in enumerate(reversed(s.split("-")))])
def iteration_utilities_chained(lst):
return sorted(lst, key=it.chained(lambda x: x.split('-'), lambda x: (int(x[1]), x[0])))
from simple_benchmark import benchmark
import random
import string
funcs = [
approach_jpp_1, approach_jpp_2, jpp_nested_lambda, toolz_compose, AshwiniChaudhary_list_comprehension,
AshwiniChaudhary_next, PaulCornelius, JeanFrançoisFabre, iteration_utilities_chained
]
arguments = {2**i: ['-'.join([random.choice(string.ascii_lowercase),
str(random.randint(0, 2**(i-1)))])
for _ in range(2**i)]
for i in range(3, 15)}
b = benchmark(funcs, arguments, 'list size')
%matplotlib notebook
b.plot_difference_percentage(relative_to=approach_jpp_2)我冒昧地包含了我自己的一个库iteration_utilities.chained的函数组合方法。
from iteration_utilities import chained
sorted(lst, key=chained(lambda x: x.split('-'), lambda x: (int(x[1]), x[0])))这是相当快(第二或第三位),但仍然慢于使用自己的功能。
请注意,如果使用具有O(n) (或更好的)算法复杂性的函数(例如min或max ),则min开销将更显着。那么键函数的常量因素就更显着了!
发布于 2018-04-05 12:19:41
我们可以将split('-')返回的列表包装在另一个列表下,然后可以使用一个循环来处理它:
# Using list-comprehension
>>> sorted(lst, key=lambda x: [(int(num), text) for text, num in [x.split('-')]])
['a-2', 'd-2', 'b-3', 'c-4']
# Using next()
>>> sorted(lst, key=lambda x: next((int(num), text) for text, num in [x.split('-')]))
['a-2', 'd-2', 'b-3', 'c-4']发布于 2018-05-26 11:23:11
lst = ['b-3', 'a-2', 'c-4', 'd-2']
res = sorted(lst, key=lambda x: tuple(f(a) for f, a in zip((int, str), reversed(x.split('-')))))
print(res)
['a-2', 'd-2', 'b-3', 'c-4']https://stackoverflow.com/questions/49671990
复制相似问题