2
votes

Conversion de boucle for en compréhension de liste

J'essaie de convertir ce qui suit en compréhension de liste, mais j'ai du mal:

aString = lorem_ipsum

counts = dict()
words = aString.split

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

Jusqu'à présent, j'ai essayé quelques variantes à ce sujet: -

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


1 commentaires

Votre fonction renvoie un dict . Comment espérez-vous en obtenir un à partir d'une liste de compréhension?


5 Réponses :


3
votes

2 commentaires

Il semble que l'utilisation des collections.Counter soit la meilleure solution, alors merci pour ce conseil. Malheureusement, j'ai une demande spécifique d'utiliser l'approche «à l'ancienne», j'ai donc utilisé votre version de compréhension qui fonctionne parfaitement. Je vous remercie.


J'éviterai également str comme nom de variable - encore une fois merci pour les conseils



3
votes

Les compréhensions ne sont pas le bon outil pour ce travail. Un collections.Counter est:

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


1 commentaires

J'ai peur d'être obligé d'utiliser le «mauvais outil», mais ce point est pris. J'essaierai d'utiliser votre bien meilleure approche lorsque je serai libre de le faire :)



1
votes

Vous pouvez utiliser count pour cela.

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


1 commentaires

J'ai corrigé la réponse.



2
votes

Ce que vous voulez vraiment, c'est une compréhension de dictionnaire, pas une compréhension de liste. Ils sont similaires, mais la syntaxe est un peu différente

>>> 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}

Le problème est que cela ne fonctionnera pas pour le problème que vous essayez de résoudre.

Les compréhensions fonctionnent soit comme une carte , où elles créent une nouvelle collection avec chaque élément transformé d'une manière ou d'une autre, soit comme un filtre , où il existe une nouvelle collection certains éléments éventuellement supprimés. Ce sont des opérations apatrides.

Le comptage de mots consiste à garder une trace des choses que vous avez déjà vues. Il s'agit d'une opération de réduction , où vous conservez l'état dans une autre structure de données, compte dans votre cas.

Comme d'autres réponses l'ont dit, collections.Counter est la "bonne" façon de résoudre ce problème.

Cela dit, voici comment utiliser une compréhension de liste pour compter les mots. Veuillez ne pas essayer cela à la maison (ou au travail ... surtout pas au travail ...)

# list comprehension
[foo for foo in stuff]

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

Cela fonctionne parce qu'une compréhension est fondamentalement une boucle for derrière le scènes, mais vous mettez toujours à jour la variable d'état et ignorez simplement la liste réelle qui est créée. Dans ce cas, il échange une utilisation accrue de la mémoire contre une meilleure lisibilité, ce n'est pas un excellent choix.


1 commentaires

Merci pour l'explication et la solution là-bas, très utile. Il semble que je doive faire quelques lectures sur les compréhensions de liste vs dict (ainsi que sur les collections). C'est un excellent pointeur



3
votes

Attention! Vous essayez d'utiliser un effet secondaire dans une compréhension de liste:

>>> 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}

essaie de mettre à jour les comptes pour chaque mot . La compréhension de liste n'est pas destinée à être utilisée comme ça.

La classe itertools.Counter est conçue pour résoudre votre problème, et vous pouvez utiliser une compréhension de dict qui compte chaque élément (voir autres réponses). Mais la compréhension de dict a une complexité O (n ^ 2): pour chaque élément de la liste, lisez la liste complète pour trouver cet élément. Si vous voulez quelque chose de fonctionnel, utilisez un pli:

>>> 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}

Pour chaque mot w , nous mettons à jour le dictionnaire actuel: d [w] est remplacé par d [w] +1 (ou 0 + 1 si w n'était pas dans d code>).

Cela donne un indice sur la façon dont vous auriez pu rédiger votre compréhension de liste:

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

Comme vous le voyez, [Aucun, Aucun, Aucun, Aucun, Aucun, Aucun, Aucun, Aucun] est la valeur de retour réelle de la compréhension de la liste. Le dictionnaire count a été mis à jour, mais ne le faites pas! . N'utilisez pas de compréhension de liste à moins d'utiliser le résultat.


1 commentaires

Merci pour l'avertissement là-bas. Compte tenu de cela et de la teneur des autres réponses ici, je vais certainement essayer d'éviter d'utiliser les compréhensions de cette manière à l'avenir.