3
\$\begingroup\$

As a challenge to myself, I wrote a solution to this Stack Overflow question. For completeness, the bulk of the question is as follows:

Problem

Input:

[
  ['key1', 'value1'],
  ['key2', 
     [
       ['key3', 'value3'],
       ['key4', 
          [
            ...
          ]
       ],
       ['key5', 'value5']
     ]
  ],
  ['key6', 'value6'],
]

Ouput:

{
  "key1": "value1",
  "key2": {
     "key3": "value3",
     "key4": ...,
     "key5": "value5"
  },
  "key6": "value6"
}

Solution

Please note that this is my first attempt.

import pprint

def main():
    lt = [ \
            ['key1', 'value1'], \
            ['key2', \
                [ \
                    ['key3', 'value3'], \
                    ['key4',  \
                        ['key7','value7'] \
                    ], \
                    ['key5', 'value5'] \
                ] \
            ], \
            ['key6', 'value6'] \
        ]
    print('Input:')
    pp = pprint.PrettyPrinter(indent=4)
    pp.pprint(lt)
    dt = lists2dict(lt, pp)
    print('-' * 80)
    print('Output:')
    pp.pprint(dt)

def lists2dict(lt, pp):
    # form a dict from a list of lists,
    # if a key's value is a single-element list, just add the element
    dt = {l[0]: l[1:] if len(l[1:]) > 1 else l[1] for l in lt}
    # print('-' * 70)
    # pp.pprint(dt)
    for k,v in dt.items(): # step through the dict, looking for places to recurse
        # print('k=%r, v=%r' %(k,v))
        if isinstance(v, list): # a value which is a list needs to be converted to a dict
            if isinstance(v[1], list): # only recurse if a to-be-parsed value has a list
                dt[k] = lists2dict(v, pp)
            else: # just a single k/v pair to parse
                dt[k] = {v[0]: v[1]}
    return dt

if __name__ == '__main__':
    main()

If anyone has improvements, or a more efficient and/or Pythonic implementation, please share it.

\$\endgroup\$
  • 2
    \$\begingroup\$ Argh! All the \ you are using when defining the input are useless. Also you should never us \ to continue a line since you can wrap whatever expression you are writing in parenthesis ( and ). \$\endgroup\$ – Bakuriu Dec 24 '13 at 18:40
  • \$\begingroup\$ All brackets in Python ((, [, and {) begin implicit line continuation. There is no need to use `` to continue a line so long as it's enclosed in a pair of matching brackets. \$\endgroup\$ – Iguananaut Dec 26 '13 at 19:28
5
\$\begingroup\$

You could simplify your function:

def nested_pairs2dict(pairs):
    d = {}
    for k, v in pairs:
        if isinstance(v, list): # assumes v is also list of pairs
           v = nested_pairs2dict(v)
        d[k] = v
    return d

It seems to work.

\$\endgroup\$
  • \$\begingroup\$ You could also shorten it further to def nested_pairs2dict(pairs): return dict((k, nested_pairs2dict(v) if isinstance(v, list) else v) for k, v in pairs) \$\endgroup\$ – 200_success Dec 24 '13 at 21:13
  • 2
    \$\begingroup\$ @200_success: I find such one-liners less readable. \$\endgroup\$ – jfs Dec 24 '13 at 21:14
  • \$\begingroup\$ Locally I get an error: for k,v in pairs // ValueError: too many values to unpack \$\endgroup\$ – kevlar1818 Dec 24 '13 at 21:41
  • \$\begingroup\$ @kevlar1818 Then you are not passing a list of 2-element lists to the function. \$\endgroup\$ – poke Dec 24 '13 at 22:33
  • \$\begingroup\$ I'd also stick with the full version for long term maintenance. This example illustrates a great python principle: doing it right is usually shorter and cleaner than doing it wrong :) \$\endgroup\$ – theodox Dec 25 '13 at 1:29

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.