对列表进行排序时嵌套的Lambda语句 [英] Nested lambda statements when sorting lists

查看:79
本文介绍了对列表进行排序时嵌套的Lambda语句的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我希望首先按数字排序,然后按文本排序.

I wish to sort the below list first by the number, then by the text.

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]))

对此我不满意,因为它需要将字符串拆分两次,以提取相关组件.

I was not happy with this since it required splitting a string twice, to extract the relevant components.

尝试2

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

I came up with the below solution. But I am hoping there is a more succinct solution via Pythonic lambda statements.

def sorter_func(x):
    text, num = x.split('-')
    return int(num), text

res = sorted(lst, key=sorter_func)

我查看了了解python中嵌套的lambda函数的行为,但是无法直接采用此解决方案.有没有更简洁的方式来重写上面的代码?

I looked at Understanding nested lambda function behaviour in python but couldn't adapt this solution directly. Is there a more succinct way to rewrite the above code?

推荐答案

在几乎所有情况下,我都会尝试第二次尝试.它是可读且简洁的(我希望每次使用三行而不是一行!)-尽管函数名可能更具描述性.但是,如果将其用作局部函数,那就没什么大不了了.

In almost all cases I would simply go with your second attempt. It's readable and concise (I would prefer three simple lines over one complicated line every time!) - even though the function name could be more descriptive. But if you use it as local function that's not going to matter much.

您还必须记住,Python使用的是key函数,而不是cmp(比较)函数.因此,要对长度为n的可迭代对象进行排序,必须精确地调用n次,但通常进行O(n * log(n))比较.因此,只要您的按键功能的算法复杂度为O(1),按键功能的调用开销就无关紧要了.那是因为:

You also have to remember that Python uses a key function, not a cmp (compare) function. So to sort an iterable of length n the key function is called exactly n times, but sorting generally does O(n * log(n)) comparisons. So whenever your key-function has an algorithmic complexity of O(1) the key-function call overhead isn't going to matter (much). That's because:

O(n*log(n)) + O(n)   ==  O(n*log(n))

有一个例外,这是Pythons sort的最佳情况:在最好的情况下,sort只进行O(n)比较,但这仅在可迭代对象已被排序(或几乎已排序)的情况下发生.如果Python具有比较功能(在Python 2中确实有一个比较功能),则该功能的常数会更为重要,因为它将被称为O(n * log(n))次(每次比较均被调用一次).

There's one exception and that's the best case for Pythons sort: In the best case the sort only does O(n) comparisons but that only happens if the iterable is already sorted (or almost sorted). If Python had a compare function (and in Python 2 there really was one) then the constant factors of the function would be much more significant because it would be called O(n * log(n)) times (called once for each comparison).

因此,不要为简洁或提高速度而烦恼(除非您可以在不引入太大常数因素的情况下减少big-O,否则您应该这样做!),首先要考虑的是可读性.因此,您实际上应该进行任何嵌套的lambda或任何其他奇特的构造(可能作为练习除外).

So don't bother about being more concise or making it much faster (except when you can reduce the big-O without introducing too big constant factors - then you should go for it!), the first concern should be readability. So you should really not do any nested lambdas or any other fancy constructs (except maybe as exercise).

长话短说,只需使用您的#2:

Long story short, simply use your #2:

def sorter_func(x):
    text, num = x.split('-')
    return int(num), text

res = sorted(lst, key=sorter_func)

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

By the way, it's also the fastest of all proposed approaches (although the difference isn't much):

摘要:它可读性强

用于重现基准的代码.它需要安装 simple_benchmark 才能运行(免责声明:这是我自己的库),但是在那里是执行此类任务的等效框架,但我对此很熟悉:

Code to reproduce the benchmark. It requires simple_benchmark to be installed for this to work (Disclaimer: It's my own library) but there are probably equivalent frameworks to do this kind of task, but I'm just familiar with it:

# 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)

我自由地包含了我自己的一个库的函数组合方法

I took the liberty to include a function composition approach of one of my own libraries iteration_utilities.chained:

from iteration_utilities import chained
sorted(lst, key=chained(lambda x: x.split('-'), lambda x: (int(x[1]), x[0])))

速度相当快(第2位或第3位),但比使用您自己的功能还慢.

It's quite fast (2nd or 3rd place) but still slower than using your own function.

请注意,如果您使用具有O(n)(或更佳)算法复杂度的函数(例如minmax),则key开销将更为显着.那么按键功能的恒定因素会更显着!

Note that the key overhead would be more significant if you used a function that had O(n) (or better) algorithmic complexity, for example min or max. Then the constant factors of the key-function would be more significant!

这篇关于对列表进行排序时嵌套的Lambda语句的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆