5
\$\begingroup\$

I have a string like "food | dairy | milk". The string may consist of more or less words. How do I turn it into a dictionary {'food': {'dairy': {'milk': {'eco': {}}}}}?

The only way I could achieve it was to create a string and then turn it into a dictionary using exec. I understand it's messy. How could I improve on it?

#!/usr/bin/env python -tt
# -*- coding: utf-8 -*-
# I have a string that represents 'path' to place where new item should be inserted
st="food | dairy | milk"
print st,"< -- string"
keys=st.split(" | ")
print keys,"<-- keys"
new_cat="eco" # should be added
d = {i:{} for i in keys}
print d,"d"
ex_str="{"
for i in keys:
 ex_str+="\""+i+"\":{"
ex_str+="\""+str(new_cat)+"\":{}"+"}"*(len(keys)+1)
exec"nd="+ex_str
print nd,"<-- new dict"
wei2912
1,2438 silver badges25 bronze badges
asked May 9, 2015 at 11:20
\$\endgroup\$

2 Answers 2

3
\$\begingroup\$

You use a temporary variable:

st="food | dairy | milk"
keys=st.split(" | ")
new_cat="eco" # should be added
d = t = {} # t is my temporary dictionary
for i in keys:
 t[i] = {}
 t = t[i]
t[new_cat] = {}
print d
answered May 9, 2015 at 11:34
\$\endgroup\$
2
\$\begingroup\$

Another way you can do it is going in reverse, like so:

st = "food | dairy | milk"
d = {}
new_cat="eco" # should be added
for key in reversed(st.split(" | ") + [new_cat]):
 d = {key: d}
print d
# {'food': {'dairy': {'milk': {'eco': {}}}}}

How this works is it starts with {}, then it does {the last key: what it is} ({'eco': {}}), then it does {the second to last key: what it is currently} ({'milk': {'eco': {}}}), and so on until the end.

But to make it more presentable, you should put it in a function. This also makes it more flexible, and allows it to work for more things.

def str_to_dict(separator, str_, *new_keys):
 d = {}
 for key in reversed(str_.split(seperator) + new_keys):
 d = {key: d}
 return d
print str_to_dict(" | ", "food | dairy | milk", "eco")
# {'food': {'dairy': {'milk': {'eco': {}}}}}
print str_to_dict("`", "food`dairy`milk", "eco", ("test",), 5)
# {'food': {'dairy': {'milk': {'eco': {('test',): {5: {}}}}}}}
answered May 10, 2015 at 18:52
\$\endgroup\$
5
  • \$\begingroup\$ It looks interesting. Could you explain what does asterisk mean. \$\endgroup\$ Commented May 10, 2015 at 19:56
  • \$\begingroup\$ @SergiiArtele The asterisk means that it can take as many arguments as it wants, and all the extra arguments will turn into a tuple called new_keys in this case. See stackoverflow.com/questions/36901/… as well. \$\endgroup\$ Commented May 10, 2015 at 19:58
  • \$\begingroup\$ for key in reversed(str_.split(separator) + new_keys): TypeError: can only concatenate list (not "tuple") to list \$\endgroup\$ Commented May 12, 2015 at 11:11
  • \$\begingroup\$ @SergiiArtele That seems to be a Python 2 issue. In that case, do reversed(str_.split(separator) + list(new_keys)) \$\endgroup\$ Commented May 12, 2015 at 14:58
  • \$\begingroup\$ THNX. Exactly, python 2.7 \$\endgroup\$ Commented May 12, 2015 at 15:14

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.