20

Consider the following:

>>> # list of length n
>>> idx = ['a', 'b', 'c', 'd']

>>> # list of length n
>>> l_1 = [1, 2, 3, 4]

>>> # list of length n
>>> l_2 = [5, 6, 7, 8]

>>> # first key
>>> key_1 = 'mkt_o'

>>> # second key
>>> key_2 = 'mkt_c'

How do I zip this mess to look like this?

{
    'a': {'mkt_o': 1, 'mkt_c': 5},
    'b': {'mkt_o': 2, 'mkt_c': 6},
    'c': {'mkt_o': 3, 'mkt_c': 6},
    'd': {'mkt_o': 4, 'mkt_c': 7},
    ...
}

The closest I've got is something like this:

>>> dict(zip(idx, zip(l_1, l_2)))
{'a': (1, 5), 'b': (2, 6), 'c': (3, 7), 'd': (4, 8)}

Which of course has tuples as values instead of dictionaries, and

>>> dict(zip(('mkt_o', 'mkt_c'), (1,2)))
{'mkt_o': 1, 'mkt_c': 2}

Which seems like it might be promising, but again, fails to meet requirements.

U13-Forward
  • 69,221
  • 14
  • 89
  • 114
Jason Strimpel
  • 14,670
  • 21
  • 76
  • 106

4 Answers4

41
{k : {key_1 : v1, key_2 : v2} for k,v1,v2 in zip(idx, l_1, l_2)}
DYZ
  • 55,249
  • 10
  • 64
  • 93
  • 1
    Please take a bow. The audience is cheering. Perfect, thanks. – Jason Strimpel Mar 27 '18 at 07:07
  • 1
    This is fastest: ```>>> sol_1 = '{k: dict(zip(["mkt_o", "mkt_c"], v)) for k, v in zip(["a", "b", "c", "d"], zip([1, 2, 3, 4], [5, 6, 7, 8]))}' >>> sol_2 = 'dict(zip(["a", "b", "c", "d"], [{"mkt_o": i, "mkt_c": j} for i, j in zip([1, 2, 3, 4], [5, 6, 7, 8])]))' >>> sol_3 = '{k : {"mkt_o" : v1, "mkt_c" : v2} for k,v1,v2 in zip(["a", "b", "c", "d"], [1, 2, 3, 4], [5, 6, 7, 8])}' >>> timeit.timeit(sol_1, number=10000) 0.05262671899981797 >>> timeit.timeit(sol_2, number=10000) 0.02170446099989931 >>> timeit.timeit(sol_3, number=10000) 0.014590603001124691``` – Jason Strimpel Mar 28 '18 at 02:43
15

Solution 1: You may use zip twice (actually thrice) with dictionary comprehension to achieve this as:

idx = ['a', 'b', 'c', 'd']
l_1 = [1, 2, 3, 4]
l_2 = [5, 6, 7, 8]

keys = ['mkt_o', 'mkt_c']   # yours keys in another list

new_dict = {k: dict(zip(keys, v)) for k, v in zip(idx, zip(l_1, l_2))}

Solution 2: You may also use zip with nested list comprehension as:

new_dict = dict(zip(idx, [{key_1: i, key_2: j} for i, j in zip(l_1, l_2)]))

Solution 3: using dictionary comprehension on top of zip as shared in DYZ's answer:

new_dict = {k : {key_1 : v1, key_2 : v2} for k,v1,v2 in zip(idx, l_1, l_2)}

All the above solutions will return new_dict as:

{
     'a': {'mkt_o': 1, 'mkt_c': 5}, 
     'b': {'mkt_o': 2, 'mkt_c': 6}, 
     'c': {'mkt_o': 3, 'mkt_c': 7},
     'd': {'mkt_o': 4, 'mkt_c': 8}
 }
Moinuddin Quadri
  • 46,825
  • 13
  • 96
  • 126
2

You're working with dicts, lists, indices, keys and would like to transpose the data. It might make sense to work with pandas (DataFrame, .T and .to_dict):

>>> import pandas as pd
>>> idx = ['a', 'b', 'c', 'd']
>>> l_1 = [1, 2, 3, 4]
>>> l_2 = [5, 6, 7, 8]
>>> key_1 = 'mkt_o'
>>> key_2 = 'mkt_c'
>>> pd.DataFrame([l_1, l_2], index=[key_1, key_2], columns = idx)
       a  b  c  d
mkt_o  1  2  3  4
mkt_c  5  6  7  8
>>> pd.DataFrame([l_1, l_2], index=[key_1, key_2], columns = idx).T
   mkt_o  mkt_c
a      1      5
b      2      6
c      3      7
d      4      8
>>> pd.DataFrame([l_1, l_2], index=[key_1, key_2], columns = idx).to_dict()
{'a': {'mkt_o': 1, 'mkt_c': 5},
 'b': {'mkt_o': 2, 'mkt_c': 6},
 'c': {'mkt_o': 3, 'mkt_c': 7},
 'd': {'mkt_o': 4, 'mkt_c': 8}
}
Eric Duminil
  • 52,989
  • 9
  • 71
  • 124
1

It can also be done with dict, zip, map and repeat from itertools:

>>> from itertools import repeat
>>> dict(zip(idx, map(dict, zip(zip(repeat(key_1), l_1), zip(repeat(key_2), l_2)))))
{'a': {'mkt_c': 5, 'mkt_o': 1}, 'c': {'mkt_c': 7, 'mkt_o': 3}, 'b': {'mkt_c': 6, 'mkt_o': 2}, 'd': {'mkt_c': 8, 'mkt_o': 4}}
Dan D.
  • 73,243
  • 15
  • 104
  • 123