2

Out of curiosity is it possible to write the following logic as a nice dict comprehension?

a = "a c\nb c\nn q\n".split('\n')[:-1]

output = {}
for line in a:
    tmp = line.split(' ')
    output[tmp[0]] = tmp[1]

I wrote the following, but without a temporary assignment I have to split twice which is unfortunate:

{line.split(' ')[0]:line.split(' ')[1] for line in a}

Is something more elegant possible?

Cœur
  • 37,241
  • 25
  • 195
  • 267
tlnagy
  • 3,274
  • 4
  • 24
  • 37
  • You could use regex to split by two dilimiters at once: http://stackoverflow.com/questions/1059559/python-strings-split-with-multiple-delimiters – zinjaai Jul 29 '14 at 13:39
  • What about using the csv package and obtaining a map using csv.DictReader? https://docs.python.org/3.4/library/csv.html – Alessandro Suglia Jul 29 '14 at 13:40

7 Answers7

7

In this case, I think the dict constructor is a little nicer since it will take an iterable of 2-sequences:

dict(line.split() for line in a)

Demo:

>>> a
['a c', 'b c', 'n q']
>>> dict(line.split() for line in a)
{'a': 'c', 'b': 'c', 'n': 'q'}
mgilson
  • 300,191
  • 65
  • 633
  • 696
  • 1
    It's really a pity that I can't accept two answers because this is actually the best solution for this specific case, but @Tichodroma's answer is more general. – tlnagy Jul 29 '14 at 13:53
  • Darn, I had tried the same with a dict comprehension which didn't work, so I thought `dict()` wouldn't either. Good to know there's a difference here. – Tim Pietzcker Jul 29 '14 at 13:55
5

Use a nested list comprehension:

{p[0]:p[1] for p in [l.split(" ") for l in a]}

Output:

{'a': 'c', 'b': 'c', 'n': 'q'}
  • Thank Guido who designed Python :) –  Jul 29 '14 at 13:51
  • 1
    I like this because this is a common problem I run into with list/dict comprehensions and this generalizes a lot better than many of the other methods, which may be better for this specific case. – tlnagy Jul 29 '14 at 13:52
  • Answer was so obvious, but I missed it. Thank you – Mo2 Aug 22 '23 at 01:34
2

Highly specific to the whitespace in your particular input:

>>> a = "a c\nb c\nn q\n".split('\n')[:-1]
>>> {line[0]:line[2] for line in a}
{'a': 'c', 'b': 'c', 'n': 'q'}
mhawke
  • 84,695
  • 9
  • 117
  • 138
0

does that work:

>>> a = "a c\nb c\nn q\n".split('\n')[:-1]

>>> {i[0]:i[1]  for line in a for i in [line.split(' ')]}
 {'a': 'c', 'b': 'c', 'n': 'q'}
Serbitar
  • 2,134
  • 19
  • 25
0

In this case, you can use

dict(line.split(' ') for line in a)

but for more complicated "value processing" I usually find it easier to use either "normal" loop (like you did) or write small helper function:

def helper(val):
    ...
    return key, value

dict(helper(line) for line in a)

This is one thing (crippled lambda/anonymous function syntax) I really hate about python.

Jan Spurny
  • 5,219
  • 1
  • 33
  • 47
0

Use a nested list comprehension without a split.

>>> {line[0]:line[-1] for line in a}
{'a': 'c', 'b': 'c', 'n': 'q'}
Gihan_G
  • 159
  • 4
0

Through python's re module,

>>> import re
>>> a = "a c\nb c\nn q\n"
>>> a
'a c\nb c\nn q\n'
>>> m = re.findall(r'^(.) (.)$', a, re.M)
>>> m
[('a', 'c'), ('b', 'c'), ('n', 'q')]
>>> dict(m)
{'a': 'c', 'b': 'c', 'n': 'q'}
Avinash Raj
  • 172,303
  • 28
  • 230
  • 274