z-wei
z-wei

Reputation: 33

Convert a string with components separated by symbols into a nested python dictionary

I'm struggling with a Python question and would appreciate any help. Do have patience, my Python is basic at the moment.


Question:

How do I transform a string structure like this:

text="key1=value1;key2=value2\nkeyA=valueA\n..."

into a Python dictionary like this:

{0:{'key1':'value1', 'key2':'value2'}, 1:{'keyA':'valueA'}}
  1. Realize that ';' separates items in the inner dictionary while ‘\n’ separates items on the outer dictionary.
  2. The key, values in the inner dictionaries are strings. The keys for the outer dictionaries are indexes.

There needs to be another function to transform this Python dictionary back into its original string form.


Where I am now:

I was thinking of creating a loop that is able to do this but I'm struggling to create it.

         a[0]["key1"]="value1"  
         a[0]["key2"]="value2"  
         a[1]["keyA"]="valueA"  

The best I did was to split the string by '\n' like this:

text ='k1=v1;k2=v2\nk3=v3\nk4=v4'
text = text.split("\n")

output: ['k1=v1;k2=v2', 'k3=v3', 'k4=v4']

And looped the elements into the dictionary like this:

dic = {}
for i,x in enumerate(text):
    dic[i] = x

output: {0: 'k1=v1;k2=v2', 1: 'k3=v3', 2: 'k4=v4'}

But how do I get these values within the dictionary into the key, value structure as seen above?

Upvotes: 3

Views: 649

Answers (3)

Anonymous
Anonymous

Reputation: 355

There may be a more clean and precise way to solve your problem but for now, You can manage with this one.

def make_dict(string):
    temp={}
    string=string.split(';')
    string=[i.split('=') for i in string]
    for a,b in string:
        temp[a]=b 
    return temp 

text ='k1=v1;k2=v2\nk3=v3\nk4=v4'
text=text.split('\n')
dic={}

for i,x in enumerate(text):
    dic[i] = make_dict(x)

>>> print(dic) 
>>> {0: {'k1': 'v1', 'k2': 'v2'}, 1: {'k3': 'v3'}, 2: {'k4': 'v4'}}

If you want to reverse the above process then it can be done by the following way.

def convert_again(dct):
    fetch_values = list(dct.values())

    change_values_to_list = [list(i.items()) for i in fetch_values]

    # add "=" in between the key-value pairs 
    for i in range(len(change_values_to_list)):
        for j in range(len(change_values_to_list[i])):
            change_values_to_list[i][j]='='.join(change_values_to_list[i][j])

    # Now add ";"
    answer = [';'.join(i) for i in change_values_to_list]
    # Now add "\n" 
    final_answer = '\\n'.join(answer)
    return final_answer

    #Driver Code

    dct= {0: {'k1': 'v1', 'k2': 'v2'}, 1: {'k3': 'v3'}, 2: {'k4': 'v4'}}
    print(convert_again(dct)) # --> "k1=v1;k2=v2\nk3=v3\nk4=v4"

Upvotes: 1

blhsing
blhsing

Reputation: 106891

You can use the following dict comprehension:

{i: dict(p.split('=', 1) for p in l.split(';')) for i, l in enumerate(text.split('\n')) if l}

With your sample input:

text="key1=value1;key2=value2\nkeyA=valueA\n"

This returns:

{0: {'key1': 'value1', 'key2': 'value2'}, 1: {'keyA': 'valueA'}}

Upvotes: 2

ababuji
ababuji

Reputation: 1731

I've written a solution that can be extended for other examples as well. I've created a more complicated example

Notice how, we have another set which is seperted by a ;. If I can demonstrate it for this example, it should work for others as well

It is important to note that this will work only if the last 2 characters in text is "\n". If "\n" is not present in the last two characters, then remove the line list1.remove("")

text="key3=value3;key4=value4\nkey1=value1;key2=value2\nkeyA=valueA\nkeyB=valueB\n"

I am first splitting by \n, that would mean that there would be an "" present in the list, since last 2 characters of text is "\n"

list1 = text.split("\n")
list1.remove("") 

Now I'm creating two lists, one to append string separated by ";" and another to append strings NOT separated by ";"

list2 = [] #Stuff seperated by ;
list3 = [] #Stuff not seperated by ;

for items in list1:

    if ';' in items:
        list2.append(items)

    else:
        list3.append(items)

I created an empty dictionary which eventually have what you want:

result_dict = {} #To store all key, value pairs

list2 now has ['key3=value3;key4=value4', 'key1=value1;key2=value2']

#First storing key, value pairs seperated by ";"
for i in range(0, len(list2)):
    a = list2[i].split(";")
    result_dict[i] = dict(s.split('=') for s in a)

list3 has ['keyA=valueA', 'keyB=valueB']

#Now storing key, value pairs not seperated by ";"
nosemicolon_dict = dict(s.split('=') for s in list3)

for key, value in nosemicolon_dict.items():
    for j in range(0, len(nosemicolon_dict)):
        result_dict[j + i + 1] = {key:value}

FOR YOUR EXAMPLE, Run the same code above, replace text with your example also ensuring to take into account whether "\n" is the last two characters in your example or not. If you DON'T have "\n" at the end of the string, remove list1.remove("") THIS LINE

print(result_dict)

gave me:

{0: {'key1': 'value1', 'key2': 'value2'}, 1: {'keyA': 'valueA'}}

Upvotes: 0

Related Questions