Конвертировать forloop в список понимания - PullRequest
2 голосов
/ 06 мая 2019

Я пытаюсь преобразовать следующее для понимания списка, но изо всех сил:

lorem_ipsum = """Lorem ipsum dolor sit amet, consectetur adipiscing elit."""

def word_count2(str):
    counts = dict()
    words = str.split() 

    for word in words:
        if word in counts:
            counts[word] += 1
        else:
            counts[word] = 1

    return counts

print(word_count2(lorem_ipsum))

До сих пор я пробовал несколько вариантов этого: -

aString = lorem_ipsum

counts = dict()
words = aString.split

[counts[word] += 1 if word in counts else counts[word] = 1 for word in words]

К сожалению, это имеетПрошло уже несколько часов, но ничего, что я пробовал, похоже, не работает

Ответы [ 5 ]

3 голосов
/ 06 мая 2019

Внимание! Вы пытаетесь использовать побочный эффект внутри понимания списка:

[counts[word] += 1 if word in counts else counts[word] = 1 for word in words]

пытается обновить counts для каждого word. Понимание списка не предназначено для такого использования.

Класс itertools.Counter предназначен для решения вашей проблемы, и вы можете использовать интеллектуальное понимание, которое учитывает каждый элемент (см. Другие ответы). Но понимание слова имеет сложность O (n ^ 2): для каждого элемента списка прочитайте полный список, чтобы найти этот элемент. Если вы хотите что-то функциональное, используйте сгиб:

>>> lorem_ipsum = """Lorem ipsum dolor sit amet, consectetur adipiscing elit."""
>>> import functools
>>> functools.reduce(lambda d, w: {**d, w: d.get(w, 0)+1}, lorem_ipsum.split(), {})
{'Lorem': 1, 'ipsum': 1, 'dolor': 1, 'sit': 1, 'amet,': 1, 'consectetur': 1, 'adipiscing': 1, 'elit.': 1}

Для каждого слова w мы обновляем текущий словарь: d[w] заменяется на d[w]+1 (или 0+1, если w не было в d).

Это дает подсказку о том, как вы могли бы написать свое понимание списка:

>>> counts = {}
>>> [counts.update({word: counts.get(word, 0) + 1}) for word in lorem_ipsum.split()]
[None, None, None, None, None, None, None, None]
>>> counts
{'Lorem': 1, 'ipsum': 1, 'dolor': 1, 'sit': 1, 'amet,': 1, 'consectetur': 1, 'adipiscing': 1, 'elit.': 1}

Как видите, [None, None, None, None, None, None, None, None] - это реальное возвращаемое значение понимания списка. Словарь count был обновлен, но не делайте этого! . Не используйте понимание списка, если вы не используете результат.

2 голосов
/ 06 мая 2019

То, что вы на самом деле просите, это понимание словаря, а не понимание списка.Они похожи, но синтаксис немного другой

# list comprehension
[foo for foo in stuff]

# dict comprehension
{key: val for key, val in some_tuple}

Проблема в том, что это не сработает для проблемы, которую вы пытаетесь решить.

Понимания работают как map, где они создают новую коллекцию с каким-то образом преобразованным каждым элементом, или filter, где существует новая коллекция с некоторыми элементами, которые могут быть удалены.Это операции без сохранения состояния.

Подсчет слов подразумевает отслеживание того, что вы уже видели.Это операция reduce, при которой вы сохраняете состояние в какой-то другой структуре данных, counts в вашем случае.

Как уже говорили другие ответы, collections.Counter - это «правильный» способ решения этой проблемы.проблема.

С учетом всего сказанного, вот как использовать понимание списка для подсчета слов.Пожалуйста, не пытайтесь делать это дома (или на работе ... особенно не на работе ...)

>>> lorem_ipsum = """
... Lorem ipsum dolor sit amet, consectetur adipiscing elit.
... """ * 2
>>> result = {}
>>> words = lorem_ipsum.split()
>>> [result.update({word: result.get(word, 0) + 1}) for word in words]
[None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None]
>>> result
{'consectetur': 2, 'ipsum': 2, 'amet,': 2, 'adipiscing': 2, 'sit': 2, 'elit.': 2, 'dolor': 2, 'Lorem': 2}

Это работает, потому что понимание - это, в основном, цикл за кулисами, но вывсе еще обновляя переменную состояния и просто игнорируя фактический список, который создается.В этом случае он торгует увеличенным использованием памяти для удобства чтения, а не лучшим выбором.

2 голосов
/ 06 мая 2019

Понимания не являются подходящим инструментом для этой работы.A collections.Counter - это:

>>> from collections import Counter
>>> counts = Counter(lorem_ipsum.split())
>>> print(counts)
Counter({'Lorem': 1, 'ipsum': 1, 'dolor': 1, 'sit': 1, 'amet,': 1, 'consectetur': 1, 'adipiscing': 1, 'elit.': 1})
>>> counts['Lorem']
1
>>> counts['foo']
0
2 голосов
/ 06 мая 2019

Для этой проблемы вам даже не нужны какие-либо списочные / словесные понимания.Просто используйте collections.Counter.

from collections import Counter
counts = Counter(lorem_ipsum.split())
# >>> print(counts)
# Counter({'ipsum': 1, 'amet,': 1, 'sit': 1, 'elit.': 1, 'consectetur': 1, 'adipiscing': 1, 'dolor': 1, 'Lorem': 1})

Если вы действительно хотите сделать это старомодным способом, вы можете сделать что-то вроде:

words = lorem_ipsum.split()
counts = { word: words.count(word) for word in words }
# >>> print(counts)
# {'ipsum': 1, 'amet,': 1, 'sit': 1, 'elit.': 1, 'consectetur': 1, 'adipiscing': 1, 'dolor': 1, 'Lorem': 1}

Кроме того, не используйте str в качестве имени переменной.Она скрывает встроенную функцию str, что делает эту функцию непригодной для использования и может привести к трудным для отладки ошибкам.

0 голосов
/ 06 мая 2019

Вы можете использовать количество для этого.

lorem_ipsum = """
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
"""

word = {word:lorem_ipsum.split().count(word) for word in lorem_ipsum.split()}
print word
...