2015-05-14 2 views
0

Как упражнение в lambdas python (просто чтобы я мог научиться правильно их использовать), я дал себе задание отсортировать строки, основанные на чем-то, отличном от их естественного строкового порядка.Python3 Сделать tie-break лямбда больше pythonic?

Я очистил apache для строк номера версии, а затем придумал лямбду, чтобы отсортировать их на основе чисел, которые я извлекал с помощью регулярных выражений. Это работает, но я думаю, что это может быть лучше, я просто не знаю, как улучшить его, чтобы он был более надежным.

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. В основном потому, что я знаю, что нет многострочного лямбды, я не знаю, как повторно использовать один regex, вместо создания второй.
  • Во-вторых, это работает только в том случае, если номера версий - это два числа, разделенные одним периодом. Первый элемент - 2.5.1, который сортируется в нужное место, но текущий метод не знает, как связать разрыв для 2.5.2, или 2.5.3, или для любой строки с произвольным количеством точек версии.

Так оно и работает, но это должен быть лучший способ сделать это. Как я могу улучшить это?

+0

Плохое использование лямбда. Это больше «Pythonic», чтобы просто написать небольшую функцию для этого. – dawg

+0

@dawg Спасибо, но это уже было сказано в ответе Игнасио Васкеса-Абрамса. –

ответ

0

Первоначально я придумал это:

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

Однако, основываясь на ответе Ignacio Vazquez-Абрамса, я сделал следующие изменения.

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

Это не полный ответ, но он доставит вас далеко по дороге к одному.

Возвращаемое значение ключевой функции может быть кортежем, и кортежи сортируются естественным образом. Вы хотите, чтобы выход от ключевой функции был следующим:

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

Обратите внимание, что это плохой вариант использования для лямбда независимо от того,

+0

Вы ответили, когда я дал свой собственный ответ. Я понимаю, о чем вы говорите. Каково надлежащее приличия? Должен ли я обновлять свой собственный ответ, чтобы соответствовать тому, что вы говорите, или я должен внести свои изменения, а затем опубликовать их в качестве комментария к вашему? –

Смежные вопросы