title: Why is Collections.counter so slow?
body: <p>I'm trying to solve a Rosalind basic problem of counting nucleotides in a given sequence, and returning the results in a list. For those ones not familiar with bioinformatics it's just counting the number of occurrences of 4 different characters ('A','C','G','T') inside a string.</p>
  
  <p>I expected <code>collections.Counter</code> to be the fastest method (first because they claim to be high-performance, and second because I saw a lot of people using it for this specific problem).</p>
  
  <p>But to my surprise <strong>this method is the slowest</strong>!</p>
  
  <p>I compared three different methods, using <code>timeit</code> and running two types of experiments:</p>
  
  <ul>
  <li>Running a long sequence few times</li>
  <li>Running a short sequence a lot of times.</li>
  </ul>
  
  <p>Here is my code:</p>
  
  <pre><code>import timeit
  from collections import Counter
  
  # Method1: using count
  def method1(seq):
      return [seq.count('A'), seq.count('C'), seq.count('G'), seq.count('T')]
  
  # method 2: using a loop
  def method2(seq):
      r = [0, 0, 0, 0]
      for i in seq:
          if i == 'A':
              r[0] += 1
          elif i == 'C':
              r[1] += 1
          elif i == 'G':
              r[2] += 1
          else:
              r[3] += 1
      return r
  
  # method 3: using Collections.counter
  def method3(seq):
      counter = Counter(seq)
      return [counter['A'], counter['C'], counter['G'], counter['T']]
  
  
  if __name__ == '__main__':
  
      # Long dummy sequence
      long_seq = 'ACAGCATGCA' * 10000000
      # Short dummy sequence
      short_seq = 'ACAGCATGCA' * 1000
  
      # Test 1: Running a long sequence once
      print timeit.timeit("method1(long_seq)", setup='from __main__ import method1, long_seq', number=1)
      print timeit.timeit("method2(long_seq)", setup='from __main__ import method2, long_seq', number=1)
      print timeit.timeit("method3(long_seq)", setup='from __main__ import method3, long_seq', number=1)
  
      # Test2: Running a short sequence lots of times
      print timeit.timeit("method1(short_seq)", setup='from __main__ import method1, short_seq', number=10000)
      print timeit.timeit("method2(short_seq)", setup='from __main__ import method2, short_seq', number=10000)
      print timeit.timeit("method3(short_seq)", setup='from __main__ import method3, short_seq', number=10000)
  </code></pre>
  
  <p>Results:</p>
  
  <pre><code>Test1: 
  Method1: 0.224009990692
  Method2: 13.7929501534
  Method3: 18.9483819008
  
  Test2:
  Method1: 0.224207878113
  Method2: 13.8520510197
  Method3: 18.9861831665
  </code></pre>
  
  <p>Method 1 is <strong>way faster</strong> than method 2 and 3 for both experiments!!</p>
  
  <p>So I have a set of questions:</p>
  
  <ul>
  <li><p>Am I doing something wrong or it is indeed slower than the other two approaches? Could someone run the same code and share the results?</p></li>
  <li><p>In case my results are correct, (and maybe this should be another question) is there a faster method to solve this problem than using method 1?</p></li>
  <li><p>If <code>count</code> is faster, then what's the deal with <code>collections.Counter</code>?</p></li>
  </ul>