2010-11-09 30 views
9

J'ai trouvé ce problème de programmation lors de l'affichage d'un travail sur SO. Je pensais que c'était assez intéressant et en tant que programmeur Python débutant, j'ai essayé de m'y attaquer. Cependant, je pense que ma solution est assez ... désordonnée ... quelqu'un peut-il faire des suggestions pour l'optimiser ou le rendre plus propre? Je sais que c'est assez trivial, mais je me suis amusé à l'écrire. Note: Python 2.6Recherche du caractère le plus fréquent dans une chaîne

Le problème:

Ecrire un pseudo-code (ou code réel) pour une fonction qui prend une chaîne et renvoie la lettre qui apparaît le plus dans cette chaîne.

Ma tentative:

import string 

def find_max_letter_count(word): 

    alphabet = string.ascii_lowercase 
    dictionary = {} 

    for letters in alphabet: 
     dictionary[letters] = 0 

    for letters in word: 
     dictionary[letters] += 1 

    dictionary = sorted(dictionary.items(), 
         reverse=True, 
         key=lambda x: x[1]) 

    for position in range(0, 26): 
     print dictionary[position] 
     if position != len(dictionary) - 1: 
      if dictionary[position + 1][1] < dictionary[position][1]: 
       break 

find_max_letter_count("helloworld") 

Sortie:

>>> 
('l', 3) 

exemple Mise à jour:

find_max_letter_count("balloon") 
>>> 
('l', 2) 
('o', 2) 
+0

Note secondaire: vous devriez lire (http://www.python.org/dev/peps/pep-0008/) [PEP 8], qui documente le style de codage Python recommandé. Les méthodes devraient être dans snake_case plutôt que mixedCase. –

+0

duplicata possible de [Comment trouver les éléments les plus communs d'une liste?] (Http://stackoverflow.com/questions/3594514/how-to-find-most-common-elements-of-a-list) – kennytm

+0

duplicata possible de [élément Python le plus commun dans une liste] (http://stackoverflow.com/questions/1518522/python-most-common-element-in-a-list) – nawfal

Répondre

18

Il y a plusieurs façons de le faire plus court. Par exemple, vous pouvez utiliser la classe Counter (en Python 2.7 ou version ultérieure):

import collections 
s = "helloworld" 
print(collections.Counter(s).most_common(1)[0]) 

Si vous n'avez pas, vous pouvez faire le décompte manuellement (2,5 ou a plus tard defaultdict):

d = collections.defaultdict(int) 
for c in s: 
    d[c] += 1 
print(sorted(d.items(), key=lambda x: x[1], reverse=True)[0]) 

Cela dit, il n'y a rien de trop terrible dans votre implémentation.

+5

['.most_common()'] (http://docs.python.org/py3k/library/collections.html#collections.Counter.most_common) .... – kennytm

+0

@KennyTM: en effet, merci! –

+1

Merci pour votre réponse (vous aussi Chris Morgan), mais je suppose que j'ai oublié de mentionner que si plusieurs caractères sont les plus fréquents, ils devraient tous être sortis. (ex: 'abcdefg' sort a = 1, b = 1, etc.) Je pensais que c'était la partie la plus difficile, d'où le désordre à la fin. J'ai édité la question. – Sunandmoon

0

Voici quelques choses que je ferais:

  • Utilisation collections.defaultdict au lieu du dict vous initialisez manuellement.
  • Utilisez le tri intégré et les fonctions maxi comme max au lieu de travailler par vous-même - c'est plus simple.

Voici mon résultat final:

from collections import defaultdict 

def find_max_letter_count(word): 
    matches = defaultdict(int) # makes the default value 0 

    for char in word: 
     matches[char] += 1 

    return max(matches.iteritems(), key=lambda x: x[1]) 

find_max_letter_count('helloworld') == ('l', 3) 
+0

Nitpicking: 'letters' serait plus correct que' letter', puisque c'est une variable qui contient exactement une lettre. – EOL

+1

@EOL: vrai; Je n'ai pas renommé cette variable de ce qu'il avait - je la mettrais moi-même en tant que «char», car ce n'est pas juste une lettre ... –

3

Si vous utilisez Python 2.7, vous pouvez rapidement faire en utilisant le module de recouvrement. collections est un module de structures de données haute performance. Lire plus à http://docs.python.org/library/collections.html#counter-objects

>>> from collections import Counter 
>>> x = Counter("balloon") 
>>> x 
Counter({'o': 2, 'a': 1, 'b': 1, 'l': 2, 'n': 1}) 
>>> x['o'] 
2 
1

Si vous voulez avoir tous les caractères avec le nombre maximum de comptes, alors vous pouvez faire une variation sur l'une des deux idées proposées jusqu'à présent:

import heapq # Helps finding the n largest counts 
import collections 

def find_max_counts(sequence): 
    """ 
    Returns an iterator that produces the (element, count)s with the 
    highest number of occurrences in the given sequence. 

    In addition, the elements are sorted. 
    """ 

    if len(sequence) == 0: 
     raise StopIteration 

    counter = collections.defaultdict(int) 
    for elmt in sequence: 
     counter[elmt] += 1 

    counts_heap = [ 
     (-count, elmt) # The largest elmt counts are the smallest elmts 
     for (elmt, count) in counter.iteritems()] 

    heapq.heapify(counts_heap) 

    highest_count = counts_heap[0][0] 

    while True: 

     try: 
      (opp_count, elmt) = heapq.heappop(counts_heap) 
     except IndexError: 
      raise StopIteration 

     if opp_count != highest_count: 
      raise StopIteration 

     yield (elmt, -opp_count) 

for (letter, count) in find_max_counts('balloon'): 
    print (letter, count) 

for (word, count) in find_max_counts(['he', 'lkj', 'he', 'll', 'll']): 
    print (word, count) 

Cela donne, par exemple:

[email protected] /tmp % python count.py 
('l', 2) 
('o', 2) 
('he', 2) 
('ll', 2) 

Cela fonctionne avec toute séquence: mots, mais aussi [ 'bonjour', 'bonjour' , 'bonjour'], par exemple.

La structure heapq est très efficace pour trouver les plus petits éléments d'une séquence sans la trier complètement. D'un autre côté, comme il n'y a pas beaucoup de lettres dans l'alphabet, vous pouvez probablement parcourir la liste des nombres triés jusqu'à ce que le nombre maximum ne soit plus trouvé, sans que cela n'entraîne de perte de vitesse sérieuse.

1

est ici façon de trouver le personnage le plus commun en utilisant un dictionnaire

message = "hello world" 
d = {} 
letters = set(message) 
for l in letters: 
    d[message.count(l)] = l 

print d[d.keys()[-1]], d.keys()[-1] 
0
def most_frequent(text): 
    frequencies = [(c, text.count(c)) for c in set(text)] 
    return max(frequencies, key=lambda x: x[1])[0] 

s = 'ABBCCCDDDD' 
print(most_frequent(s)) 

frequencies est une liste de tuples qui comptent les caractères (character, count). Nous appliquons max aux tuples en utilisant count et retournons character de ce tuple. En cas d'égalité, cette solution n'en choisira qu'une seule.

-1
#file:filename 
#quant:no of frequent words you want 

def frequent_letters(file,quant): 
    file = open(file) 
    file = file.read() 
    cnt = Counter 
    op = cnt(file).most_common(quant) 
    return op 
+0

Merci pour cet extrait de code, qui pourrait fournir un peu de temps, immédiat Aidez-moi. Une explication appropriée [améliorerait considérablement] (// meta.stackexchange.com/q/114762) sa valeur à long terme en montrant * pourquoi * ceci est une bonne solution au problème, et le rendrait plus utile aux futurs lecteurs avec d'autres questions similaires. S'il vous plaît [modifier] votre réponse pour ajouter quelques explications, y compris les hypothèses que vous avez faites. Plus précisément, d'où vient Counter? –

+0

Le compteur doit être importé en utilisant la commande 'from collections import Counter' –

+0

S'il vous plaît [modifier] votre réponse pour afficher les informations supplémentaires, plutôt que de l'écrire comme commentaire. Les commentaires peuvent disparaître sans laisser de trace, donc cela doit vraiment faire partie de votre réponse. Je vous remercie. –