2010-11-09 11 views
9

Encontré este problema de programación al buscar un trabajo publicado en SO. Pensé que era bastante interesante y, como principiante en el programador de Python, traté de abordarlo. Sin embargo, creo que mi solución es bastante ... desordenada ... ¿alguien puede hacer alguna sugerencia para optimizarla o hacerla más limpia? Sé que es bastante trivial, pero me divertí escribiéndolo. Nota: Python 2.6Encontrar el carácter más frecuente en una cadena

El problema:

escritura pseudo-código (o código real) para una función que toma en una cadena y devuelve la letra que aparece la mayor cantidad en esa cadena.

Mi intento:

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

Salida:

>>> 
('l', 3) 

ejemplo Actualizado:

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

Nota incidental: debe leer [PEP 8] (http://www.python.org/dev/peps/pep-0008/), que documenta el estilo de codificación de Python recomendado. Los métodos deben estar en snake_case en lugar de mixedCase. –

+0

posible duplicado de [¿Cómo encontrar los elementos más comunes de una lista?] (Http://stackoverflow.com/questions/3594514/how-to-find-most-common-elements-of-a-list) – kennytm

+0

posible duplicado de [elemento más común de Python en una lista] (http://stackoverflow.com/questions/1518522/python-most-common-element-in-a-list) – nawfal

Respuesta

18

Hay muchas maneras de hacer esto más corto. Por ejemplo, puede utilizar la clase Counter (en Python 2.7 o posterior):

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

Si usted no tiene eso, se ha de hacer el recuento manual (2.5 o posterior tiene defaultdict):

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

Habiendo dicho eso, no hay nada demasiado terriblemente mal con su implementación.

+5

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

+0

@KennyTM: de hecho, ¡gracias! –

+1

Gracias por su respuesta (usted también Chris Morgan), pero supongo que olvidé mencionar que si varios caracteres son los más frecuentes, todos deberían mostrarse. (Ej. 'abcdefg' produce a = 1, b = 1, etc.) Pensé que esta era la parte más difícil, de ahí el desastre al final. He editado la pregunta. – Sunandmoon

0

Éstas son algunas cosas que haría:

  • Uso collections.defaultdict en lugar de la dict de que arranque de forma manual.
  • Utilice la clasificación incorporada y funciones máximas como max en lugar de resolverlo usted mismo, es más fácil.

aquí está mi resultado 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' sería más correcto como' letter', ya que es una variable que contiene exactamente una letra. – EOL

+1

@EOL: verdadero; No cambié el nombre de esa variable de la que tenía; la pondría como 'char', creo, ya que no es solo una letra ... –

3

Si está utilizando Python 2.7, puede hacerlo de forma rápida mediante el uso de este módulo de colecciones. colecciones es un módulo de estructuras de datos de alto rendimiento. Ver más en 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 usted quiere tener todos los personajes con el máximo número de recuentos, entonces usted puede hacer una variación en una de las dos ideas propuestas hasta el momento:

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) 

Este rendimientos, por ejemplo:

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

Esto funciona con cualquier secuencia: palabras, sino también [ 'hola', 'hola' , 'bonjour'], por ejemplo.

La estructura heapq es muy eficiente para encontrar los elementos más pequeños de una secuencia sin ordenarla por completo. Por otro lado, dado que no hay tantas letras en el alfabeto, probablemente también pueda ejecutar la lista ordenada de recuentos hasta que ya no se encuentre el recuento máximo, sin que esto suponga una pérdida de velocidad importante.

1

Aquí está la manera de encontrar el personaje más común el uso de un diccionario

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 es una lista de tuplas que cuentan los personajes como (character, count). Aplicamos max a las tuplas usando count y devolvemos esa tupla a character. En caso de empate, esta solución elegirá solo una.

-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

Gracias por este fragmento de código, que podría proporcionar algunos ejemplos limitados e inmediatos. ayuda. Una explicación adecuada [mejoraría en gran medida] (// meta.stackexchange.com/q/114762) su valor a largo plazo mostrando * why * esta es una buena solución al problema, y ​​lo haría más útil para los lectores futuros con otras preguntas similares. Por favor [edite] su respuesta para agregar alguna explicación, incluidas las suposiciones que ha hecho. Específicamente, ¿de dónde vino 'Counter'? –

+0

El contador debe importarse utilizando el comando 'del contador de importación de cobros' –

+0

Por favor, [edite] su respuesta para mostrar la información adicional, en lugar de escribirla como comentario. Los comentarios pueden desaparecer sin dejar rastros, por lo que realmente debe ser parte de su respuesta. Gracias. –

Cuestiones relacionadas