0

I'm trying to create a nested dictionary from a tuple. This tuple is arranged this way:

content=(p0,a0,b0,c0,d0,p1,a1,b1,c1,d1,....)

I'm trying to transform it in a nested dictionary that looks this way:

my_dictionary=[{"p":"p0","a":"a0","b":"b0","c":"c0","d":"d0"},
"p":"p1","a":"a1","b":"b1","c":"c1","d":"d1"},
"p":"p2","a":"a2","b":"b2","c":"c2","d":"d2"},
...]

The keys are always the same keys=[p,a,b,c,d]. My issue is that I don't know how to set this loop and how to format this in order to get the dictionary.

jonrsharpe
  • 115,751
  • 26
  • 228
  • 437
jaimebw
  • 25
  • 9
  • 4
    Which part of that are you stuck on *specifically*? See e.g. https://stackoverflow.com/q/434287/3001761. Note that your desired output is a *list of dictionaries*; a nested dictionary would normally be a dictionary whose values are also dictionaries. – jonrsharpe Jan 21 '20 at 21:11
  • 1
    Loop through the indexes of the tuple in strides of 5, and create a dictionary with each 5 elements, and append them to the list. – Barmar Jan 21 '20 at 21:17
  • I'm voting to close this. The expected output is ambiguous and there's no evidence of any attempt or effort. – AMC Jan 22 '20 at 00:48

2 Answers2

1

This is an alternate solution. Basically, you are moving forward in the list by chunks and creating dicts that way. This is not the shortest approach, but it might be easier for a developer to understand.

keys = ('p', 'a', 'b', 'c', 'd')
index = 0
key_len = len(keys)
content_len = len(content)

output = []
while index < content_len:
    # This grabs enough values in content from the current index to match the keys
    current_content = content[index:index + key_len]

    # This creates a structure [(keys[0], current_content[0]), (keys[1], ...
    # if current_content = [1,2,3,4,5] then zip will give us something close to
    # [('p', 1),('a', 2),('b', 3),('c', 4),('d', 5)] 
    matches = zip(keys, current_content)
    # Note on the above: based on your version of Python, the output of zip may change. 
    # (In Py3k, it creates a "zip object", in Python 2.x it creates a list)
    # That will not affect this loop.

    # A list of two-entry tuples can be passed as the parameter to the `dict` class.
    current_dict = dict(matches)

    # append the output
    output.append(current_dict)

    # Be sure to move forward in the list
    index += key_len
cwallenpoole
  • 79,954
  • 26
  • 128
  • 166
0

I can think of two ways, based on the same idiomatic way of grouping elements from a sequence:

import itertools as it


content = range(50)
keys = ('p', 'a', 'b', 'c', 'd')

dicts = [dict(zip(keys, gr)) for gr in zip(*[iter(content)]*len(keys))]
print(dicts)

dicts2 = [dict(pairs) for pairs in zip(*[iter(zip(it.cycle(keys), content))]*len(keys))]
print(dicts2)

produces

[{'p': 0, 'a': 1, 'b': 2, 'c': 3, 'd': 4}, {'p': 5, 'a': 6, 'b': 7, 'c': 8, 'd': 9}, {'p': 10, 'a': 11, 'b': 12, 'c': 13, 'd': 14}, {'p': 15, 'a': 16, 'b': 17, 'c': 18, 'd': 19}, {'p': 20, 'a': 21, 'b': 22, 'c': 23, 'd': 24}, {'p': 25, 'a': 26, 'b': 27, 'c': 28, 'd': 29}, {'p': 30, 'a': 31, 'b': 32, 'c': 33, 'd': 34}, {'p': 35, 'a': 36, 'b': 37, 'c': 38, 'd': 39}, {'p': 40, 'a': 41, 'b': 42, 'c': 43, 'd': 44}, {'p': 45, 'a': 46, 'b': 47, 'c': 48, 'd': 49}]

[{'p': 0, 'a': 1, 'b': 2, 'c': 3, 'd': 4}, {'p': 5, 'a': 6, 'b': 7, 'c': 8, 'd': 9}, {'p': 10, 'a': 11, 'b': 12, 'c': 13, 'd': 14}, {'p': 15, 'a': 16, 'b': 17, 'c': 18, 'd': 19}, {'p': 20, 'a': 21, 'b': 22, 'c': 23, 'd': 24}, {'p': 25, 'a': 26, 'b': 27, 'c': 28, 'd': 29}, {'p': 30, 'a': 31, 'b': 32, 'c': 33, 'd': 34}, {'p': 35, 'a': 36, 'b': 37, 'c': 38, 'd': 39}, {'p': 40, 'a': 41, 'b': 42, 'c': 43, 'd': 44}, {'p': 45, 'a': 46, 'b': 47, 'c': 48, 'd': 49}]

The first way creates each dictionary pairing the chunk it gets from the contents with the keys.

In terms of performance it takes

5.92 µs ± 42.2 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

The second way first pairs the contents with the keys by repeating the keys alongside them, then it takes chunks of such pairs and creates a dictionary from them.

It takes slightly less, at

5.76 µs ± 46.2 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

Note: in case the number of the input elements is not a multiple of the number of keys, the first solution can be modified to accommodate a partial dictionary

dicts = [dict((k,v) for k,v in zip(keys, gr) if v is not None) for gr in it.zip_longest(*[iter(content)]*len(keys))]

I understand it's not easy to explain how the chunking works to somebody who has just started with Python.

As cited in the comments, please refer to this SO QA for further details

Pynchia
  • 10,996
  • 5
  • 34
  • 43
  • Just tried both methods, and they work perfectly. Thank you very much Pynchia. First weeks programming in Python :P. – jaimebw Jan 21 '20 at 22:30