Search code examples
listdictionarypythonpython-itertools

Converting a single ordered list in python to a dictionary, pythonically


I can't seem to find an elegant way to start from t and result in s.

>>>t = ['a',2,'b',3,'c',4]
#magic
>>>print s
{'a': 2, 'c': 4, 'b': 3}

Solutions I've come up with that seems less than elegant :

s = dict()
for i in xrange(0, len(t),2): s[t[i]]=t[i+1]
# or something fancy with slices that I haven't figured out yet

It's obviously easily solved, but, again, it seems like there's a better way. Is there?


Solution

  • I'd use itertools, but, if you think that's complicated (as you've hinted in a comment), then maybe:

    def twobytwo(t):
      it = iter(t)
      for x in it:
        yield x, next(it)
    
    d = dict(twobytwo(t))
    

    or equivalently, and back to itertools again,

    def twobytwo(t):
      a, b = itertools.tee(iter(t))
      next(b)
      return itertools.izip(a, b)
    
    d = dict(twobytwo(t))
    

    or, if you insist on being inline, in a season-appropriate "trick or treat" mood:

    d = dict((x, next(it)) for it in (iter(t),) for x in it)
    

    me, I consider this a trick, but some might find it a treat. IOW, I find this kind of thing scary, but apparently in the US around this time of the years things are supposed to be;-).

    Basically, the problem boils down to "how do I walk a list 2 items at a time", because dict is quite happy to take a sequence of 2-tuples and make it into a dictionary. All the solutions I'm showing here ensure only O(1) extra space is taken (beyond the space, obviously O(N), that's needed for the input list and the output dict, of course).

    The suggested approach in the docs (everybody should be familiar with that page, the itertool recipes) is the function pairwise on that page, which is basically the second one I suggested here. I do think every site-packages directory should contain an iterutils.py file with those recipes (pity such a file's not already a part of python's stdlib!-).