سؤال

I have a string like this

PARAMS = 'TEST = xy; TEST2= klklk '

which I want to split twice, once at the ";" and second on the "=" and then put it in a dict.

I can do it with this line:

dict(item.split("=") for item in PARAMS.split(";"))

and get:

{' TEST2': ' klklk ', 'TEST ': ' xy'}

I would now also like to strip the key and value before putting them in the dict. Is there an elegant way to do it in one line in python?

هل كانت مفيدة؟

المحلول 2

dict([i.strip() for i in item.split("=")] for item in PARAMS.split(";"))

This runs a lot faster than @aIKid's solution :)

PARAMS = 'TEST = xy; TEST2= klklk '
from timeit import timeit
print timeit('dict((i.strip() for i in item.split("=")) for item in PARAMS.split(";"))', "from __main__ import PARAMS")
print timeit('dict([i.strip() for i in item.split("=")] for item in PARAMS.split(";"))', "from __main__ import PARAMS")

Output

18.7284784281
9.16360774723

نصائح أخرى

I don't know exactly what you call 'elegant', but this works:

dict((i.strip() for i in item.split("=")) for item in PARAMS.split(";"))

Maybe something like:

dict(map(lambda x: x.strip(), item.split("=")) for item in PARAMS.split(";"))

or another even more elegant version:

dict((l[i].strip(), l[i+1].strip()) for i in range(2) for l in [re.split(';|=', PARAMS)])

Of course this is elegant only if you take it as a synonym of obfuscated, but when we are seeking one-liners is it not what we mean ?

To solve this problem I would probably write:

d = dict(); 
for item in PARAMS.split(";"):
    key, value = item.split("=")
    d[key.strip()] = value.strip()

It is both easier to read and faster than all the proposed answer until now, and I didn't even bothered to optimize it in any way, henceforth it is probably not the best possible solution.

Don't believe it on words, time the different solutions to check:

PARAMS = 'TEST = xy; TEST2= klklk '

from timeit import timeit

print 'obfuscated', timeit('dict((l[i].strip(), l[i+1].strip()) for i in range(2) for l in [re.split(";|=", PARAMS)])', "from __main__ import PARAMS; import re")
print 'tuple', timeit('dict((i.strip() for i in item.split("=")) for item in PARAMS.split(";"))', "from __main__ import PARAMS")
print 'regex', timeit('dict(re.findall(r"(\S+)\s*=\s*([^\s;]+)", PARAMS))', "from __main__ import PARAMS; import re")
print 'lambda', timeit('dict(map(lambda x: x.strip(), item.split("=")) for item in PARAMS.split(";"))', "from __main__ import PARAMS; import re")
print 'list comprehension', timeit('dict([i.strip() for i in item.split("=")] for item in PARAMS.split(";"))', "from __main__ import PARAMS")
print 'replace spaces', timeit('dict(item.split("=") for item in PARAMS.replace(" ", "").split(";"))', "from __main__ import PARAMS; import re")

print 'not one line', timeit(
'''
    d = dict(); 
    for item in PARAMS.split(";"):
        key, value = item.split("=")
        d[key.strip()] = value.strip()
    d
''',
"from __main__ import PARAMS")

Below are the timing results:

  • obfuscated: 7.36826086044
  • tuple: 4.49374079704
  • regex: 3.61684799194
  • lambda: 3.51627087593
  • list comprehension: 2.90777206421
  • replace spaces: 2.46001887321
  • not one line: 1.71015286446

It speaks for itself.

PS: the reason why the not one line is faster is probably because it avoids creating an unecessary list structure, but directly store value in the dict. But that was a no brainer, not even voluntary.

Or, alternatively:

import re
text = 'TEST = xy; TEST2= klklk '
params = dict(re.findall(r'(\S+)\s*=\s*([^\s;]+)', text))
# {'TEST': 'xy', 'TEST2': 'klklk'}

If none of your keys or values have spaces inside them, then you're free to eliminate all spaces with a single replace method:

>>> dict(item.split("=") for item in PARAMS.replace(" ", "").split(";"))
{'TEST': 'xy', 'TEST2': 'klklk'}

This will eliminate more spaces than strip would, of course:

>>> PARAMS = 'TEST 3 = there should be spaces between these words '
>>> dict(item.split("=") for item in PARAMS.replace(" ", "").split(";"))
{'TEST3': 'thereshouldbespacesbetweenthesewords'}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top