Home > Software engineering >  How can I transform a value from a dictionary to a key and build a nested dictionary with the subseq
How can I transform a value from a dictionary to a key and build a nested dictionary with the subseq

Time:01-30

I'm new to dict structures and I have the following:

d = {'a': 'aa', 'b': 'bb', 'c': 'cc', 'x':111, 'y': 222, 'z':333}

And I want to change to the following structure:

d2 = {'a': 'aa', 'b': 'bb', 'cc':{ 'x':111, 'y': 222, 'z':333}}

Basically, the value of a given key will become the key itself and subsequent values will go into this new key as a nested dict.The values of x, y and z are demonstrative only, they can be floats or integers. Always after the c key, will come the values that need to be placed inside c. Thank you

CodePudding user response:

A tricky solution would be to use pandas.DataFrame constructor from :

import pandas as pd

def nest_dict(d, val):
    v = next((k for k, v in d.items() if v == val), None)
    df = pd.DataFrame(d, index=[0])
    idx = df.columns.get_loc(v)
    out = df.iloc[:, :idx].to_dict("records")[0]
    out[val] = df.iloc[:, idx 1:].to_dict("records")[0]
    return out

d2 = nest_dict(d1, "cc")

Output :

print(d2)
#{'a': 'aa', 'b': 'bb', 'cc': {'x': 111, 'y': 222, 'z': 333}}

CodePudding user response:

This seems like a vague question and more details regarding the constraints/rules should be provided. However, with the given details, here is a piece of code that should help you out.

import itertools
def slice_dic(dic, k):
    keys = list(dic)
    lts = keys.index(k)
    d = dict(itertools.islice(dic.items(), lts))
    d2 = dict(itertools.islice(dic.items(), lts 1,len(keys)))
    d[list(dic.values())[lts]] = d2
    return d

input_dict = {'a': 'aa', 'b': 'bb', 'c': 'cc', 'x':111, 'y': 222, 'z':333}
slice_dic(input_dict, "c") #slices the dictionary at c 
                  #and keeps all subsequent key:value pairs as a dictinoary

The above snippet gives the following output:

{'a': 'aa', 'b': 'bb', 'cc': {'x': 111, 'y': 222, 'z': 333}}

CodePudding user response:

With limited information present and without using any libraries

def spl_dict(d, pos):
    d2 = dict(list(d.items())[:pos-1])
    d2[list(d.values())[pos-1]]= dict(list(d.items())[pos:])
    return d2
print(spl_dict(d,3))

Output :

{'a': 'aa', 'b': 'bb', 'cc': {'x': 111, 'y': 222, 'z': 333}}

CodePudding user response:

Here is a little longer solution fitted for more general cases:

d = {'a': 'aa', 'b': 'bb', 'c': 'cc', 'x':111, 'y': 222, 'z':333}

slicing_key = 'c'
svalue = d[slicing_key]

d2 = {}
d2[svalue] = {}

# List of all keys
all_keys = list(d.keys())
# Index of the key where you slice
slice_ind = all_keys.index(slicing_key)
# Unchanged entries
orig_keys = all_keys[:slice_ind]
# Keys for entries in the inner dict
new_keys = all_keys[slice_ind 1:]

# Assemble the new dictionary
for key in orig_keys:
    d2[key] = d[key]

for key in new_keys:
    d2[svalue][key] = d[key]

First you pre-define your output dictionary, then you split up the list of all keys based on your slicing key criterion, and finally you assemble the new dictionary.

Note that this relies on the fact that the list returned by keys() is ordered. It should be this way now but you can also sort it to be on the safe side, all_keys = list(sorted(d.keys())).

CodePudding user response:

Assuming that you hold an insertion order of your input dict, the solution with itertools.groupby util to get sequential groups counting on c key:

from itertools import groupby

d = {'a': 'aa', 'b': 'bb', 'c': 'cc', 'x':111, 'y': 222, 'z':333}
head, c, tail = [list(gr) for _, gr in groupby(d.items(), lambda t: t[0] == 'c')]
c_k, c_v = c[0]  # for c key
res = {**dict(head), **{c_v: dict(tail)}}

{'a': 'aa', 'b': 'bb', 'cc': {'x': 111, 'y': 222, 'z': 333}}
  • Related