Gabriele Picco Gabriele Picco - 1 month ago 24
Python Question

Most frequently occuring n words in a string

I have a problem with the following problem:

Problem:

Implement a function count_words() in Python that takes as input a string s and a number n, and returns the n most frequently-occuring words in s. The return value should be a list of tuples - the top n words paired with their respective counts [(, ), (, ), ...], sorted in descending count order.

You can assume that all input will be in lowercase and that there will be no punctuations or other characters (only letters and single separating spaces). In case of a tie (equal count), order the tied words alphabetically.

E.g.:

print count_words("betty bought a bit of butter but the butter was bitter",3)
Output:

[('butter', 2), ('a', 1), ('betty', 1)]

This is my solution:

"""Count words."""

from operator import itemgetter
from collections import Counter

def count_words(s, n):
"""Return the n most frequently occuring words in s."""

# TODO: Count the number of occurences of each word in s
words = s.split(" ");
words = Counter(words)
# TODO: Sort the occurences in descending order (alphabetically in case of ties)
print(words)
# TODO: Return the top n words as a list of tuples (<word>, <count>)
top_n = words.most_common(n)
return top_n

def test_run()

"""Test count_words() with some inputs."""
print(count_words("cat bat mat cat bat cat", 3))
print(count_words("betty bought a bit of butter but the butter was bitter", 3))


if __name__ == '__main__':
test_run()


The problem is that elements with equal counts are ordered arbitrarily, how can i order that elements by alphabetical order ??

Answer

You can sort them using the number of occurrence (in reverse order) and then the lexicographical order:

>>> lst = [('meat', 2), ('butter', 2), ('a', 1), ('betty', 1)]
>>> 
>>> sorted(lst, key=lambda x: (-x[1], x[0]))
#                              ^ reverse order 
[('butter', 2), ('meat', 2), ('a', 1), ('betty', 1)]

The number of occurrence takes precedence over the lex. order.

In your case, use words.items() in place of the list of the list I have used. You will no longer need to use most_common as sorted already does the same.