2

At the moment I have the following as a way of putting the characters in a sort of visual text-map into a dict. I am wondering though, if there's a really nice concise, pythonic way of doing this double iteration. Any ideas?

lines = ['abc','456','xyz']
chars = {}
for i, row in enumerate(lines):
    for j, c in enumerate(row):
        chars[i,j] = c
3
  • 1
    I think this is about as readable as the equivalent dictionary comprehension. Commented Jan 26, 2013 at 17:51
  • Your original code is fine! Commented Jan 26, 2013 at 18:13
  • chars = map(list, lines) creates a 2d list that allows to change the strings e.g., chars[i][j] = 'c'. You could also use bytearray instead of list here depending on how chars is used. Commented Jan 26, 2013 at 19:19

2 Answers 2

4

You could express it as a dictionary comprehension:

chars = {(i, j): c for i, row in enumerate(lines) for j, c in enumerate(row)}

It's fundamentally the same iteration, only expressed a bit differently.

Sign up to request clarification or add additional context in comments.

4 Comments

@freestyler: this is just fine; once you are used to the comprehensions syntax this is equally clear as the original.
@MartijnPieters I'm not entirely convinced, it simply crams everything on one line, by virtually the same reasoning, you could advocate using semicolons to get more on one line.
@phant0m: I think it's entirely personal preference. I agree with Martijn in that the more of a particular syntax one sees, the easier on the eye it becomes. I personally find the two versions to have about the same readability, and have no strong preference either way.
I agree with freestyler, this is less readable. OP's original code can be read line by line, left to right. The comprehensions syntax uses variables before defining them, so your eye has to jump about.
3

Use a dict comprehension. The key to reading nested comprehensions: "Just read them like normal loops, with the “big loop” described first and the subsequent loops nested inside of it" 1

In [1]: lines = ['abc','456','xyz']

In [2]: {(i,j): c for i, row in enumerate(lines) for j, c in enumerate(row)}
Out[2]: 
{(0, 0): 'a',
 (0, 1): 'b',
 (0, 2): 'c',
 (1, 0): '4',
 (1, 1): '5',
 (1, 2): '6',
 (2, 0): 'x',
 (2, 1): 'y',
 (2, 2): 'z'}

You can split the comprehension to multiple lines, to make it more readable. If you look closely it is actually very similar to a regular loop, only the last line is brought to the start.

In addition to that I would recommend reading a blog post by Brandon Rhodes: "I finally understand nested comprehensions"

# Comprehension                       # Regular for loop

{(i,j):c                              # chars = {}
    for i, row in enumerate(lines)    # for i, row in enumerate(lines):
        for j, c in enumerate(row)}   #     for j, c in enumerate(row):
                                      #          chars[i,j] = c

1 Comment

This is really the same as NPE's answer.

Your Answer

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.