首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >排序列表时嵌套的lambda语句

排序列表时嵌套的lambda语句
EN

Stack Overflow用户
提问于 2018-04-05 12:07:19
回答 7查看 5K关注 0票数 15

我希望先按编号,然后按案文对以下清单进行排序。

代码语言:javascript
复制
lst = ['b-3', 'a-2', 'c-4', 'd-2']

# result:
# ['a-2', 'd-2', 'b-3', 'c-4']

尝试1

代码语言:javascript
复制
res = sorted(lst, key=lambda x: (int(x.split('-')[1]), x.split('-')[0]))

我对此并不满意,因为它需要分割一个字符串两次,以提取相关组件。

尝试2

我想出了下面的解决方案。但我希望通过Pythonic lambda语句有一个更简洁的解决方案。

代码语言:javascript
复制
def sorter_func(x):
    text, num = x.split('-')
    return int(num), text

res = sorted(lst, key=sorter_func)

我看了理解python中的嵌套lambda函数行为,但无法直接适应这个解决方案。有没有一种更简洁的方法来重写上面的代码?

EN

回答 7

Stack Overflow用户

回答已采纳

发布于 2018-07-06 21:21:41

在几乎所有的情况下,我都会同意你的第二次尝试。它具有可读性和简洁性(每次我更喜欢三行简单的行,而不是一行复杂的行!)--尽管函数名可能更具有描述性。但是如果你用它作为局部函数,那就不重要了。

您还必须记住,Python使用的是key函数,而不是cmp (比较)函数。因此,要对可迭代的长度n进行排序,key函数被调用为精确的n时间,但是排序通常会进行O(n * log(n))比较。因此,每当您的密钥函数具有O(1)算法复杂性时,键函数调用开销就不会有多大影响。那是因为

代码语言:javascript
复制
O(n*log(n)) + O(n)   ==  O(n*log(n))

有一个例外,这是Pythons sort最好的情况:在最好的情况下,sort只进行O(n)比较,但只有在迭代已经排序(或几乎排序)的情况下才会发生。如果Python有一个比较函数(在Python2中确实有一个),那么函数的常量因素就会更重要,因为它将被称为O(n * log(n))时间(每次比较调用一次)。

所以,不要为了更简洁或者让它更快而烦恼(除非你可以在不引入太大的常数因素的情况下减少大的O,那么你应该去做!),首先要考虑的应该是可读性。因此,您应该真正地,而不是,做任何嵌套的lambda或任何其他花哨的构造(除了作为练习)。

长话短说,只需使用你的第二个:

代码语言:javascript
复制
def sorter_func(x):
    text, num = x.split('-')
    return int(num), text

res = sorted(lst, key=sorter_func)

顺便说一句,也是所有提议的方法中最快的(尽管差别不大):

摘要:它是可读的和快速的

复制基准测试的代码。它需要安装simple_benchmark才能使其工作(免责声明:这是我自己的库),但是可能有类似的框架来完成这类任务,但我只是熟悉它:

代码语言:javascript
复制
# 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的函数组合方法。

代码语言:javascript
复制
from iteration_utilities import chained
sorted(lst, key=chained(lambda x: x.split('-'), lambda x: (int(x[1]), x[0])))

这是相当快(第二或第三位),但仍然慢于使用自己的功能。

请注意,如果使用具有O(n) (或更好的)算法复杂性的函数(例如minmax ),则min开销将更显着。那么键函数的常量因素就更显着了!

票数 3
EN

Stack Overflow用户

发布于 2018-04-05 12:19:41

我们可以将split('-')返回的列表包装在另一个列表下,然后可以使用一个循环来处理它:

代码语言:javascript
复制
# 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']
票数 7
EN

Stack Overflow用户

发布于 2018-05-26 11:23:11

代码语言:javascript
复制
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']
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/49671990

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档