#python #for-loop #dictionary-comprehension
#python #для-цикл #понимание словаря
Вопрос:
Мне нужно найти самую длинную строку в списке для каждой буквы алфавита. Мой первый прямой подход выглядел так:
alphabet = ["a","b", ..., "z"]
text = ["ane4", "anrhgjt8", "andhjtje9", "ajhe5", "]more_crazy_words"]
result = {key:"" for key in alphabet} # create a dictionary
# go through all words, if that word is longer than the current longest, save it
for word in text:
if word[0].lower() in alphabet and len(result[word[0].lower()]) < len(word):
result[word[0].lower()] = word.lower()
print(result)
который возвращает:
{'a': 'andhjtje9'}
как и предполагалось.
Чтобы практиковать понимание словаря, я попытался решить это всего за одну строку:
result2 = {key:"" for key in alphabet}
result2 = {word[0].lower(): word.lower() for word in text if word[0].lower() in alphabet and len(result2[word[0].lower()]) < len(word)}
Я просто скопировал оператор if в цикл понимания…
results2 однако:
{'a': 'ajhe5'}
может кто-нибудь объяснить мне, почему это так? Я чувствую, что сделал точно так же, как и в первом цикле…
Спасибо за любую помощь!
Комментарии:
1. вы используете предыдущие значения
result2
, которые сохраняют пустые строки в качестве значения до тех пор, пока не будет вычислено понимание dict2.
for
необходимо включитьalphabet
и найти слово максимальной длины путем фильтрации по первому символу и построения кортежей(length, string)
, затем найти max с помощью ключевой функции, а затем извлечь строку найденного максимума3.Вы можете применить
groupby()
:{g: i for g, (*_, i) in groupby(sorted(text, key=lambda x: (len(x), x[0])), itemgetter(0)) if 96 < ord(g) < 123}
. Импортирует:groupby()
,itemgetter()
(вы можете заменитьitemgetter(0)
наlambda x: x[0]
). Я использовал коды символов ascii для фильтрацииa .. z
, проверьте таблицу ASCII.4. @PatrickArtner, извините за мой mistake…it возвращает ‘andhjtje9’… Я отредактирую сообщение
5. @rioV8 спасибо, это было в основном объяснение, которое я искал! Я не понимал, что он все еще сравнивает значения с пустой строкой, поскольку новый dict еще не создан, тогда как в «классическом» цикле for это так!
Ответ №1:
List / Dict / Set — понимание не может ссылаться на себя при создании самого себя — вот почему вы не получаете то, что хотите.
Для этого вы можете использовать сложное понимание словаря — с помощью collections.groupby в отсортированном списке это может выглядеть так:
from string import ascii_lowercase
from itertools import groupby
text = ["ane4", "anrhgjt8", "andhjtje9", "ajhe5", "]more_crazy_words"]
d = {key:sorted(value, key=len)[-1]
for key,value in groupby((s for s in sorted(text)
if s[0].lower() in frozenset(ascii_lowercase)),
lambda x:x[0].lower())}
print(d) # {'a': 'andhjtje9'}
или
text = ["ane4", "anrhgjt8", "andhjtje9", "ajhe5", "]more_crazy_words"]
d = {key:next(value) for key,value in groupby(
(s for s in sorted(text, key=lambda x: (x[0],-len(x)))
if s[0].lower() in frozenset(ascii_lowercase)),
lambda x:x[0].lower())}
print(d) # {'a': 'andhjtje9'}
или несколькими другими способами … но зачем вам это нужно?
Использование его как для циклов намного чище и проще для понимания, и в этом случае, вероятно, лучше следовать дзен python.
Прочитайте о дзен python, выполнив:
import this
Комментарии:
1. Я также предпочитаю базовую версию цикла… Я просто пробовал это на практике и был смущен, почему это не работает. Но спасибо за ваш ответ! отличное решение проблемы 🙂
2. Groupby не нужен, если вы просто предварительно сортируете по начальной букве и длине (т. Е. Последним, выигрывает):
{i[0]: i for i in sorted(map(str.lower, text), key=lambda i: (i[0], len(i))) if i[0] in alphabet}
.3. @ekh с помощью groupby я избегаю повторной установки значения одного ключа снова и снова — ваш устанавливает значение для каждого ключа для всех значений, начиная с самого короткого, а затем перезаписывает их все более длинными, пока не сохранится самое длинное значение. Допустимый подход, я предпочитаю группирующую конструкцию. Спасибо за предложение.
4. @ekhumoro, слишком сильно говорить «не требуется», потому что предложенный вами подход совершенно иной, он основан на том факте, что значение ключа будет переписываться каждый раз. Говоря об «оптимизации», вы можете избежать использования
map()
, опустив первый символ в вашем лямбда-выражении.5. @PatrickArtner Повторная установка значения — это именно то, что делает идиоматическое решение для цикла (т. Е. Последнее, выигрывает). Попытка преобразования OP в понимание dict завершилась неудачей, поскольку для этого потребовался поиск по самому себе. Мое решение успешно, потому что оно позволяет избежать этого поиска путем предварительной сортировки входных данных. Это показывает, что можно приблизиться к тому, чего пытался достичь OP, без использования
groupby
.