title: Efficiently Compacting a List of Tuples to a Dictionary of Lists in Python?
body: <h2>Question</h2>
  
  <p>I am interested in finding a more efficient (<em>code complexity, speed, memory usage, comprehensions, generators</em>) method of reducing a list of two element tuples, where the first element may be duplicated between the elements, to a dictionary of lists.</p>
  
  <pre><code>from copy import deepcopy
  a = [('a', 'cat'), ('a', 'dog'), ('b', 'pony'), ('c', 'hippo'), ('c','horse'), ('d', 'cow')]
  
  b = {x[0]: list() for x in a}
  
  c = deepcopy(b)
  for key, value in b.items():
      for item in a:
          if key == item[0]:
              c[key].append(item[1])
  print(a)
  print(c)
  </code></pre>
  
  <blockquote>
    <p>[('a', 'cat'), ('a', 'dog'), ('b', 'pony'), ('c', 'hippo'), ('c', 'horse'), ('d', 'cow')]</p>
    
    <p>{'a': ['cat', 'dog'], 'b': ['pony'], 'c': ['hippo', 'horse'], 'd': ['cow']}</p>
  </blockquote>
  
  <h2>Answer Testing</h2>
  
  <pre><code>from collections import defaultdict
  from itertools import groupby
  from operator import itemgetter
  import timeit
  
  timings = dict()
  
  def wrap(func, *args, **kwargs):
      def wrapped():
          return func(*args, **kwargs)
      return wrapped
  
  a = [('a', 'cat'), ('a', 'dog'), ('b', 'pony'), ('c', 'hippo'), ('c','horse'), ('d', 'cow')]
  
  # yatu's solution
  def yatu(x):
      output = defaultdict(list)
      for item in x:
          output[item[0]].append(item[1])
      return output
  
  # roseman's solution
  def roseman(x):
      d = defaultdict(list)
      for key, value in a:
          d[key].append(value)
      return d
  
  # prem's solution
  def prem(a):
      result = {k: [v for _,v in grp] for k,grp in groupby(a, itemgetter(0))}
      return result
  
  # timings
  yatus_wrapped = wrap(yatu, a)
  rosemans_wrapped = wrap(roseman, a)
  prems_wrapped = wrap(prem, a)
  timings['yatus'] = timeit.timeit(yatus_wrapped, number=100000)
  timings['rosemans'] = timeit.timeit(rosemans_wrapped, number=100000)
  timings['prems'] = timeit.timeit(prems_wrapped, number=100000)
  
  # output results
  print(timings)
  </code></pre>
  
  <blockquote>
    <p>{'yatus': 0.171220442, 'rosemans': 0.153767728, 'prems': 0.22808025399999993}</p>
  </blockquote>
  
  <p><strong>Roseman's solution is marginally the fastest, thank you.</strong></p>