3

I have a long list of lists formatted like this:

[
  [
    'iyr:1928',
    'cid:150',
    'pid:476113241',
    'eyr:2039',
    'hcl:a5ac0f',
    'ecl:#25f8d2',
    'byr:2027',
    'hgt:190'
  ],
  [
    'hgt:168cm',
    'eyr:2026',
    'ecl:hzl',
    'hcl:#fffffd',
    'cid:169',
    'pid:920076943',
    'byr:1929',
    'iyr:2013'
  ],
  ...
]

And I want to convert it to a list of dicts like this:

[
    {
        "iyr": "1928",
        "cid": "150",
        "pid": "476113241",
        "eyr": "2039",
        "hcl": "a5ac0f",
        "ecl": "#25f8d2",
        "byr": "2027",
        "hgt": "190"
    },
    {
        "hgt": "168cm",
        "eyr": "2026",
        "ecl": "hzl",
        "hcl": "#fffffd",
        "cid": "169",
        "pid": "920076943",
        "byr": "1929",
        "iyr": "2013"
    },
    ...
]

I understand that I have to split(':') each entry in each list, but I don't know how I could then convert that block into a dict.

Georgy
  • 12,464
  • 7
  • 65
  • 73
Buster
  • 446
  • 5
  • 16
  • 4
    It's better to include what have you tried so far and what's unexpected result of yours – Gahan Dec 05 '20 at 09:50
  • You should've figured out first how to convert a single list to a dict and then extend the solution to multiple lists. For a single list see: [Convert list of strings to dictionary](https://stackoverflow.com/q/22980977/7851470) – Georgy Dec 11 '20 at 12:51

5 Answers5

3
  [{entry.split(':')[0] : entry.split(':')[1] for entry in entries} for entries in myarray]
Tarik
  • 10,810
  • 2
  • 26
  • 40
2

You can go over each item in the list, then for each item (which is a list), go over its items, split them by : (as you suggested!) and use the first item as a key and the second as a value.

Using list and dict comprehensions, this can even be a oneliner:

result = [{s.split(':')[0]:s.split(':')[1] for s in l} for l in lst]
Mureinik
  • 297,002
  • 52
  • 306
  • 350
1

I like short but easy and readable versions, so probably I would do it like this:

make_dict = lambda list_item : {x.split(':')[0]:x.split(':')[1] for x in list_item}
l1 = [make_dict(item) for item in org_list]
swag2198
  • 2,546
  • 1
  • 7
  • 18
1

Along with the other more concise answers, here's a more verbose version that does the same thing

def list_to_dict(elements):
  elem_dict = {}
  for elem in elements:
    k, v = elem.split(":")
    elem_dict[k] = v
  return elem_dict


list_of_lists = [
  [
    'iyr:1928',
    'cid:150',
    'pid:476113241',
    'eyr:2039',
    'hcl:a5ac0f',
    'ecl:#25f8d2',
    'byr:2027',
    'hgt:190'
  ],
  [
    'hgt:168cm',
    'eyr:2026',
    'ecl:hzl',
    'hcl:#fffffd',
    'cid:169',
    'pid:920076943',
    'byr:1929',
    'iyr:2013'
  ],
]

list_of_dicts = map(list_to_dict, list_of_lists)

print(list_of_lists)
print(list_of_dicts)
Shadab
  • 1,297
  • 6
  • 9
1

This answer does also account for multiple : in your strings and does not rely on indexing the list:

lol = [
  [
    'iyr:1928',
    'cid:150',
    'pid:476113241',
    'eyr:2039',
    'hcl:a5ac0f',
    'ecl:#25f8d2',
    'byr:2027',
    'hgt:190'
  ],
  [
    'hgt:168cm',
    'eyr:2026',
    'ecl:hzl',
    'hcl:#fffffd',
    'cid:169',
    'pid:920076943',
    'byr:1929',
    'iyr:2013'
  ]
]

res = [dict([tuple(i.split(':', maxsplit=1)) for i in l]) for l in lol]
print(res)
'''
[
  {
    "iyr":"1928",
    "cid":"150",
    "pid":"476113241",
    "eyr":"2039",
    "hcl":"a5ac0f",
    "ecl":"#25f8d2",
    "byr":"2027",
    "hgt":"190"
  },
  {
    "hgt":"168cm",
    "eyr":"2026",
    "ecl":"hzl",
    "hcl":"#fffffd",
    "cid":"169",
    "pid":"920076943",
    "byr":"1929",
    "iyr":"2013"
  }
]
'''

cProfiling yields:

cProfile.run('res = [dict([tuple(i.split(":", maxsplit=1)) for i in l]) for l in lol]')

         20 function calls in 0.000 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000    0.000    0.000 <string>:1(<listcomp>)
        1    0.000    0.000    0.000    0.000 <string>:1(<module>)
        1    0.000    0.000    0.000    0.000 {built-in method builtins.exec}
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}
       16    0.000    0.000    0.000    0.000 {method 'split' of 'str' objects}

in comparison to the accepted solutions which yields:

cProfile.run('res = [{entry.split(":")[0] : entry.split(":")[1] for entry in entries} for entries in myarray]')

         38 function calls in 0.000 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        2    0.000    0.000    0.000    0.000 <string>:1(<dictcomp>)
        1    0.000    0.000    0.000    0.000 <string>:1(<listcomp>)
        1    0.000    0.000    0.000    0.000 <string>:1(<module>)
        1    0.000    0.000    0.000    0.000 {built-in method builtins.exec}
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}
       32    0.000    0.000    0.000    0.000 {method 'split' of 'str' objects}

and thus my proposed solution does scale better for large lists of lists as mentioned by OP.

tafaust
  • 1,457
  • 16
  • 32