Here was my attempt at finding the most frequent integers in a list, I feel like there are better ways to do this and I spent a great deal of time coming up with this solution, so please point me in the correct direction!

Created on Jan 27, 2018
Problem statement: Find the most frequently occuring integer in a list and its occurence;
    input: 1 1 2 3 2 1 2
    output: [(1,3), (2, 3)]

@author: Anonymous3.1415
from collections import Counter

def integer_frequency(int_list):
    int_freq = Counter()
    for i in int_list:
        int_freq[i] += 1
    cnt = 0
    values = sorted(int_freq.values())
    for x in values:
        if x == values[0]:
            cnt += 1
    return int_freq.most_common(cnt)

int_list = list(map(int, raw_input().strip().split(' ')))
most_frequent = integer_frequency(int_list)
  • 1
    \$\begingroup\$ watch out for an empty input list. There's currently no validation in place and it will raise a ValueError (unless the problem states your input will always be non-empty!) \$\endgroup\$ – chatton Jan 27 '18 at 23:48
  • 1
    \$\begingroup\$ Somewhat trivial, but since I think documentation is important: occurrence, occurring take two 2 rs. As a matter of habit, spelling matters. I work in a trilingual office, and I can't tell you the number of times we've missed parts of a length refactoring because half of us write it phonetically (in our accent) as lenght. \$\endgroup\$ – msanford Jan 29 '18 at 14:49

You could use itertools.takewhile to keep on taking tuples until they are not the same count anymore:

from collections import Counter
from itertools import takewhile

def integer_frequency(integers):
    int_freq = Counter(integers)
    most_common = int_freq.most_common(1)[0]
    return list(takewhile(lambda x: x[1] == most_common[1],

I also renamed your integer_list to integers, because it can be any iterable of integers.

Alternatively, you could use itertools.groupby to group the tuples by their frequency and return the group with the highest frequency, as @Gareth Reese has suggested in the comments:

from collections import Counter
from itertools import groupby

def integer_frequency(integers):
    return list(next(groupby(Counter(integers).most_common(),
                             key=lambda x: x[1]))[1])

This approach is consistently faster (by a small amount):

enter image description here

However, both beat your algorithm by quite a lot:

enter image description here

  • 1
    \$\begingroup\$ If you're going down the itertools route, I think groupby would be a little bit clearer than takewhile. That is, list(next(groupby(Counter(integers).most_common(), key=lambda x:x[1]))[1]) \$\endgroup\$ – Gareth Rees Jan 29 '18 at 14:06
  • \$\begingroup\$ @GarethRees Not sure if it is any clearer with those nested calls, but it is a nice alternative. I added it to the answer. \$\endgroup\$ – Graipher Jan 29 '18 at 14:12
  • \$\begingroup\$ @GarethRees Added some timings and groupby seems to be consistently faster than takewhile (but not by much). Both are a lot better than the OP's approach, though. \$\endgroup\$ – Graipher Jan 29 '18 at 14:34
  • 1
    \$\begingroup\$ In real code you'd use variables instead of nested function applications, but I only have this little comment box to type into! The reason why the groupby approach is faster is that it avoids a duplicate call to most_common. \$\endgroup\$ – Gareth Rees Jan 29 '18 at 14:43

There are some things that will make this code cleaner and faster. int_freq = Counter(int_list) will automatically initialize the counter without you doing work. Also values = sorted(int_freq.values(), reverse=True) will be cleaner and faster. Other than that this looks pretty good.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.