-1

I'm practicing some python syntax exercises and I decided to write a dictionary comprehension based on a similarly designed list comprehension. But while the later is OK, the former results in a syntax error.

This is my list comprehension..

>>> l = [z**z if z%2 else z for z in range(5)]
[0, 1, 2, 27, 4]

and this is my dictionary comprehension..

>>> d = {z:z**z if z%2 else z:z for z in range(5)}
                             ^
    SyntaxError: invalid syntax

is there a way to write a dictionary comprehension that is similar in design to my list comprehension?

Paperclip Bob
  • 346
  • 2
  • 8

3 Answers3

1

You can just write

In [16]: d = {z:z**z if z%2 else z for z in range(5)}
In [17]: d
Out[17]: {0: 0, 1: 1, 2: 2, 3: 27, 4: 4}

which is easier to read if you supply parentheses:

In [18]: d = {z:(z**z if z%2 else z) for z in range(5)}
In [19]: d
Out[19]: {0: 0, 1: 1, 2: 2, 3: 27, 4: 4}

The enclosed part is a Python ternary expression for the value, not for the (key, value) pair.

@timgeb but what if he also wants to change the key too in the else?

(Let's assume we want z*10.) In cases like this, you could write something like

In [24]: d = {(z*10 if z%2 else z):(z**z if z%2 else z) for z in range(5)}
In [25]: d
Out[25]: {0: 0, 10: 1, 4: 4, 2: 2, 30: 27}

but this is inefficient because z%2 is computed twice.

It is better to make use of the fact that the dict constructor takes an iterable of two-element iterables:

In [26]: dict((z*10, z**z) if z%2 else (z, z) for z in range(5))
Out[26]: {0: 0, 10: 1, 4: 4, 2: 2, 30: 27}
timgeb
  • 76,762
  • 20
  • 123
  • 145
  • If the computed condition is expensive, a slightly more efficient way to avoid repeating it is like this: `{(z*10 if k else z):(z**z if k else z) for z in range(5) for k in [z%2]}`. – ekhumoro Apr 15 '18 at 18:14
  • @ekhumoro that's pretty clever, but in the end using the `dict` constructor with tuples still wins :) – timgeb Apr 15 '18 at 18:16
  • For me, `dict()` is about 20% slower than the comprehensions. (Tested using `timeit`, with 100k iterations). – ekhumoro Apr 15 '18 at 18:23
  • @ekhumoro Interesting! Then only readability and `k` with complex `__bool__` implementations remain to be discussed. :) – timgeb Apr 15 '18 at 19:46
0

Try:

{z:z**z if z%2 else z for z in range(5)}

Output:

{0: 0, 1: 1, 2: 2, 3: 27, 4: 4}
[Finished in 0.2s]
rahul mehra
  • 418
  • 2
  • 13
0
d = {z:z**z if z%2 else z for z in range(5)}
print(d)

Gives output:

{0: 0, 1: 1, 2: 2, 3: 27, 4: 4}