Python3让打破平局的lambda排序更加pythonic?

时间:2015-05-14 23:20:24

标签: sorting python-3.x lambda

作为python lambdas中的一个练习(只是这样我可以学习如何更好地使用它们)我给自己做了一个赋值,根据除了它们的自然字符串顺序之外的东西来排序一些字符串。

我为版本号字符串删除了apache,然后想出了一个lambda来根据我用regexes提取的数字对它们进行排序。它有效,但我认为可能更好,我只是不知道如何改进它,因此它更健壮。

from lxml import html
import requests
import re

# Send GET request to page and parse it into a list of html links
jmeter_archive_url='https://archive.apache.org/dist/jmeter/binaries/'
jmeter_archive_get=requests.get(url=jmeter_archive_url)
page_tree=html.fromstring(jmeter_archive_get.text)
list_of_links=page_tree.xpath('//a[@href]/text()')

# Filter out all the non-md5s. There are a lot of links, and ultimately
# it's more data than needed for his exercise
jmeter_md5_list=list(filter(lambda x: x.endswith('.tgz.md5'), list_of_links))

# Here's where the 'magic' happens. We use two different regexes to rip the first
# and then the second number out of the string and turn them into integers. We
# then return them in the order we grabbed them, allowing us to tie break.
jmeter_md5_list.sort(key=lambda val: (int(re.search('(\d+)\.\d+', val).group(1)), int(re.search('\d+\.(\d+)', val).group(1))))
print(jmeter_md5_list)

这确实有所需效果,输出为:

['jakarta-jmeter-2.5.1.tgz.md5', 'apache-jmeter-2.6.tgz.md5', 'apache-jmeter-2.7.tgz.md5', 'apache-jmeter-2.8.tgz.md5', 'apache-jmeter-2.9.tgz.md5', 'apache-jmeter-2.10.tgz.md5', 'apache-jmeter-2.11.tgz.md5', 'apache-jmeter-2.12.tgz.md5', 'apache-jmeter-2.13.tgz.md5']

因此我们可以看到字符串被分类为有意义的顺序。最低版本第一版和最高版本。我在解决方案中看到的直接问题是双重的。

  • 首先,我们必须创建两个不同的正则表达式来获取我们想要的数字而不是仅仅捕获组1和2.主要是因为我知道没有多行lambda,我不知道如何重用单个正则表达式而不是创建第二个。
  • 其次,只有版本号是由一个句点分隔的两个数字时才有效。第一个元素是2.5.1,它被排序到正确的位置,但是当前方法不知道如何为2.5.2或2.5.3绑定中断,或者对于具有任意数量的版本点的任何字符串

所以它有效,但必须有更好的方法。我怎样才能改善这个?

2 个答案:

答案 0 :(得分:1)

这不是一个完整的答案,但它会让你走得很远。

键函数的返回值可以是元组,元组自然排序。您希望键功能的输出为:

((2, 5, 1), 'jakarta-jmeter')
((2, 6), 'apache-jmeter')
etc.

请注意,无论如何,这对于lambda来说都是一个糟糕的用例。

答案 1 :(得分:0)

最初,我想出了这个:

jmeter_md5_list.sort(key=lambda val: list(map(int, re.compile('(\d+(?!$))').findall(val))))

然而,根据Ignacio Vazquez-Abrams的回答,我做了以下修改。

def sortable_key_from_string(value):
        version_tuple = tuple(map(int, re.compile('(\d+(?!$))').findall(value)))
        match = re.match('^(\D+)', value)
        version_name = ''
        if match:
                version_name = match.group(1)
        return (version_tuple, version_name)

和此:

jmeter_md5_list.sort(key = lambda val: sortable_key_from_string(val))