# Convert data into dictionary

I am trying to convert "Random = 1" into dictionary {"Random":1} I tried

Key = (line.split('=')[0]).split()[0] #to get key and remove spaces
value = (line.split('=')[1]).split()[0]
CQ_Options[Key] = value


How could I do it in more mature way?

• Why do you want to do this? Because, if you want to parse name-value contained files, I prefer the ConfigParser lib Apr 10 '17 at 12:23
• @andras.tim is right. In cases like this where the input is presumed from an uncontrolled outside source (file) in a non-strict format (optional spaces surrounding =), it is better to use a standard lib. Other benefits in this case, include ignoring comment lines. The only time home-grown one-offs are both safe & easy is when the input is also controlled by you (i.e. a companion microservice passing URL args.) Apr 10 '17 at 17:02
• Agree with @andras.tim. If at all possible, use a standard format with existing parsers, e.g. INI, JSON, YAML, even XML is better than custom. In the event that using preexisting formats isn't an option for you, consider pyparsing. Apr 11 '17 at 0:40
• @andras.tim I am quite new to python and exploring utilities of it so I thought of not using existing libraries.
– NGB
Apr 11 '17 at 6:25

## 4 Answers

First off, you should standardize your names, Key and value don't follow the same naming rules, or if they do, they're not apparent to me. And so I'd recommend that you name your things in lower_snake_case, to adhere to PEP8.

After this I'd use str.strip rather than str.split. And use a list comprehension to change both the key and value without having to duplicate the code, which can remove the key and value variables altogether. This can leave you with:

item = [i.strip() for i in line.split('=')]
CQ_options[item[0]] = item[1]


If you want to stick with using key and value however, you need to make sure that line.split('=') will only return two items. You can make sure it'll return a max of two items with the optional parameter, and since we'd already error if there's not at least a single =, then you can use:

key, value = [i.strip() for i in line.split('=', 1)]
CQ_options[key] = value


You can use a dict comprehension if you have multiple items in a list, for example:

a = ["Random = 1", "Ran = 3"]
print {k.strip(): int(v.strip()) for k, v in (i.split("=") for i in a)}

>>> {'Ran': 3, 'Random': 1}


If you want to update an existing dictionary d:

d.update({k.strip(): int(v.strip()) for k, v in (i.split("=") for i in a)})

• Sorry I changed my answer completely, the first one was no very helpful! Apr 10 '17 at 12:51
• This answer shows how to use a dict comprehension Apr 10 '17 at 15:08
• print {k.strip(): int(v.strip()) for k, v in [line.split("=")]} would be the way to split the OP one-line data source. But that's only a few characters shorter than just explicitly doing the also-confusing print {line.split("=")[0].strip() : int(line.split("=")[-1].strip())} --all that to say, I don't think dict comprehension is a good fit here. Apr 10 '17 at 22:19

Another naive approach would be to take advantage of the fact that default split() uses whitespace, and discard the = delimiter.

line = "Random = 1"
my_dict = { line.split()[0] : line.split()[2]}


Note that the un-used value of line.split()[1] is = in this case, but could be : or anything. But this is naive in that it requires spaces.

A little better:

import re
line = "Random= 1"
my_dict = { re.split(' |=',line)[0] : re.split(' |=',line)[-1] }


Both examples yield {'Random': '1'} but the latter is more flexible. But better yet, try a standard lib like configparser which has other nice features like ignoring comment lines.

If you have one key-value pair per line, and you just want to parse all lines and transform them into a dictionary:

import re
...
CQ_Options = dict(re.split(r'\s*=\s*', line, 1) for line in text.splitlines())


I don't know if you're familiar with regular expressions or Python in general so I'll explain.

This will:

• First split text into lines and remove newline characters. The splitlines method will take care of \r aka CR on Windows.
• Then each line is split by the regular expression \s*=\s*:
• \s is whitespace, such as spaces and tabs
• * is zero or more repetitions of the previous expression, in this case zero or more whitespace characters
• the argument 1 means it will only split at the first occurrence, not all occurrences
• so the line is split by the first equals sign preceded and followed by an arbitrary amount of spaces, tabs, etc.
• Then you have a sequence of key-value pairs.
• These will be converted into a dictionary using the dict constructor, which given a sequence of key-value pairs converts them into a dictionary.

EDIT

@Peilonrayz has pointed out that this will not strip whitespace on the outer side of the key-value pair. For example " key = value " will become {' key': 'value '}. I originally assumed whitespace would be only between the key, equals sign, and value.

To remove whitespace on both sides of key and value:

CQ_Options = dict(
map(str.strip, line.split('=', maxsplit=1))
for line in text.splitlines()
)

• This doesn't remove white space around each key and value. ' abc = def ' will become {' abc': 'def '}. Also obligatory XKCD. Apr 10 '17 at 10:35
• Come on. Don't tell me you don't ever find RE useful. You're right about the whitespace but guess what, it can be solved by using regular expressions. Actually the whole thing can be done using a single finditer. Apr 10 '17 at 10:38
• Yes I do find them useful, here maybe they're overkill, and over-reliance leads to problems. Apr 10 '17 at 10:41
• @Peilonrayz Well, there's another XKCD :-P Apr 10 '17 at 10:54
• * actually means 0 or more, + means 1 or more repetitions. Apr 10 '17 at 13:08