47 votes

histogramme python sur une ligne

Il y a plusieurs façons d'écrire un programme en Python qui calcule un histogramme.

Par histogramme, je veux dire une fonction qui compte le nombre de survenance d'objets dans un iterable et sorties le compte dans un dictionnaire. Par exemple:

>>> L = 'abracadabra'
>>> histogram(L)
{'a': 5, 'b': 2, 'c': 1, 'd': 1, 'r': 2}

Une façon d'écrire cette fonction est:

def histogram(L):
    d = {}
    for x in L:
        if x in d:
            d[x] += 1
        else:
            d[x] = 1
    return d

Il n'y a plus concis façons d'écrire cette fonction?

Si nous avions dictionnaire des inclusions en Python, nous pourrions écrire:

>>> { x: L.count(x) for x in set(L) }

mais depuis la version 2.6 de Python n'en ont pas, nous avons à écrire:

>>> dict([(x, L.count(x)) for x in set(L)])

Bien que cette approche peut être lisible, il n'est pas efficace: L a marche à travers de multiples fois. En outre, cela ne fonctionne pas pour une seule vie, des générateurs de la fonction devrait fonctionner tout aussi bien pour l'itérateur générateurs tels que:

def gen(L):
    for x in L:
        yield x

Nous pourrions essayer d'utiliser l' reduce de la fonction (R. I. P.):

>>> reduce(lambda d,x: dict(d, x=d.get(x,0)+1), L, {}) # wrong!

Oups, cela ne fonctionne pas: le nom de la clé est - 'x', pas x. :(

J'ai fini avec:

>>> reduce(lambda d,x: dict(d.items() + [(x, d.get(x, 0)+1)]), L, {})

(En Python 3, il nous faudrait écrire list(d.items()) au lieu de d.items(), mais c'est hypothethical, car il n'y a pas d' reduce , là.)

Merci de me battre avec une meilleure, plus lisible one-liner! ;)

76voto

Eli Courtwright Points 53071

Python 3.x n'ont reduce, vous avez juste à faire un from functools import reduce. Il a également le "dict interprétations", qui ont exactement la syntaxe dans votre exemple.

Python 2.7 et 3.x ont également un Compteur de classe qui fait exactement ce que vous voulez:

from collections import Counter
cnt = Counter("abracadabra")

En Python 2.6 ou plus tôt, je serais personnellement utiliser un defaultdict et de le faire en 2 lignes:

d = defaultdict(int)
for x in xs: d[x] += 1

C'est propre, efficace, Pythonic, et beaucoup plus facile pour la plupart des gens à comprendre que tout ce qui concernait l' reduce.

7voto

gnibbler Points 103484

Il est un peu risqué d'importer des modules pour les imprimeurs, alors voici un exemple qui s'appelle O (n) et fonctionne au moins aussi loin que Python2.4

 >>> f=lambda s,d={}:([d.__setitem__(i,d.get(i,0)+1) for i in s],d)[-1]
>>> f("ABRACADABRA")
{'A': 5, 'R': 2, 'B': 2, 'C': 1, 'D': 1}
 

Et si vous pensez que les méthodes __ sont des hacky, vous pouvez toujours le faire.

 >>> f=lambda s,d=lambda:0:vars(([setattr(d,i,getattr(d,i,0)+1) for i in s],d)[-1])
>>> f("ABRACADABRA")
{'A': 5, 'R': 2, 'B': 2, 'C': 1, 'D': 1}
 

:)

6voto

perl Points 57
$d{$_} += 1 for split //, 'abracadabra';

5voto

Walter Cacau Points 81

Pour Python 2.7, vous pouvez utiliser cette compréhension de liste réduite:

 v = list('abracadabra')
print {x: v.count(x) for x in set(v)}
 

4voto

dgulino Points 31

Celui qui fonctionne à la version 2.3 (légèrement plus court que celui de Timmerman, je pense plus lisible):

 L = 'abracadabra'
hist = {}
for x in L: hist[x] = hist.pop(x,0) + 1
print hist
{'a': 5, 'r': 2, 'b': 2, 'c': 1, 'd': 1}
 

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X