5
\$\begingroup\$

Character Picture Grid

Say you have a list of lists where each value in the inner lists is a one-character string, like this:

grid = [['.', '.', '.', '.', '.', '.'],
        ['.', 'O', 'O', '.', '.', '.'],
        ['O', 'O', 'O', 'O', '.', '.'],
        ['O', 'O', 'O', 'O', 'O', '.'],
        ['.', 'O', 'O', 'O', 'O', 'O'],
        ['O', 'O', 'O', 'O', 'O', '.'],
        ['O', 'O', 'O', 'O', '.', '.'],
        ['.', 'O', 'O', '.', '.', '.'],
        ['.', '.', '.', '.', '.', '.']]

You can think of grid[x][y] as being the character at the x- and y-coordinates of a “picture” drawn with text characters. The (0, 0) origin will be in the upper-left corner; the x-coordinates increase going right, and the y-coordinates increase going down.

Copy the previous grid value, and write code that uses it to print the image.

..OO.OO..
.OOOOOOO.
.OOOOOOO.
..OOOOO..
...OOO...
....O....

My solution:

def logic_grid(grid):
    for x in range(6):
        for y in range(9):
            if y < 8:
                print(grid[y][x], end='')
            else:
                print(grid[y][x])

def main():
    grid = [['.', '.', '.', '.', '.', '.'],
            ['.', 'O', 'O', '.', '.', '.'],
            ['O', 'O', 'O', 'O', '.', '.'],
            ['O', 'O', 'O', 'O', 'O', '.'],
            ['.', 'O', 'O', 'O', 'O', 'O'],
            ['O', 'O', 'O', 'O', 'O', '.'],
            ['O', 'O', 'O', 'O', '.', '.'],
            ['.', 'O', 'O', '.', '.', '.'],
            ['.', '.', '.', '.', '.', '.']]
    start = logic_grid(grid)
    

if __name__ == '__main__':
    main()
\$\endgroup\$
1
  • \$\begingroup\$ As it is, your grid represents a list of columns. Would it also be acceptable to rearrange the data to have a list of rows instead, or is this a hard requirement? \$\endgroup\$
    – Schmuddi
    Jun 13, 2023 at 17:01

4 Answers 4

7
\$\begingroup\$

In Python, you rarely need to iterate using indexes. Iterate directly over the values themselves, not their indexes. [The latter is what programmers working in poorer languages have to do.]

Question the assignment. In my opinion, the function should not take a grid and print it. Rather, it should return the grid as a string. The latter is more flexible and more in line with the general principle of organizing programs around data-oriented, side-effect-free functions.

Don't hard-code the function to one specific grid. A key purpose of functions is to generalize behavior so it can be reused. If the function hardcodes the grid's dimensions, that generality disappears.

Python iterables can be joined together into strings. This is a basic operation. Take advantage of it.

def main():
    # Printing happens out at this level.
    grid = [...]
    print(grid_to_str(grid))
    

def grid_to_str(grid):
    # No side effects here. Just data in and data out.
    # As noted by RootTwo, we have to transpose the grid.
    return '\n'.join(
        ''.join(row)
        for row in zip(*grid)
    )

if __name__ == '__main__':
    main()

\$\endgroup\$
3
  • 1
    \$\begingroup\$ The grid is stored by columns. So the '\n'.join(''.join(row) ... ) would result in a picture on its side. \$\endgroup\$
    – RootTwo
    Jun 13, 2023 at 7:25
  • 5
    \$\begingroup\$ @RootTwo Unfortunate. Rotate your monitor? \$\endgroup\$
    – FMc
    Jun 13, 2023 at 7:42
  • 4
    \$\begingroup\$ That call to map is unnecessary, you can just write for row in zip(*grid). \$\endgroup\$
    – Seb
    Jun 13, 2023 at 9:35
5
\$\begingroup\$

Currently you are making assumptions in logic_grid about grid. With the current setup it's fine, but if later grid becomes larger/smaller, the image will not print correctly. Instead of hardcoding in values for the array length, use len

def logic_grid(grid):
    # adding validation here to make sure grid is initialized would also be a good idea
    for x in range(len(grid[0])):
        for y in range(len(grid)):
            if y < len(grid)-1:
                print(grid[y][x], end='')
            else:
                print(grid[y][x])

I would also suggest using a better function name as logic_grid doesn't do anything besides printing, so something like print_grid or display_grid would describe what the function does much better.

\$\endgroup\$
2
  • \$\begingroup\$ How do you mean validation? \$\endgroup\$ Jun 12, 2023 at 12:59
  • \$\begingroup\$ @JarneVercruysse validation like type(grid) is list and len(grid)>0) \$\endgroup\$
    – depperm
    Jun 12, 2023 at 13:41
4
\$\begingroup\$

You can use zip to transpose the itearble of iterables. Like this:

print('\n'.join(''.join(i) for i in zip(*grid)))

(and this code above is the solution)

Another example: dot product of two math vectors with zip

dot_product = lambda x,y:sum(i*j for i,j in zip(x,y))
\$\endgroup\$
1
\$\begingroup\$

You don't need zip() and you don't need len(). Just concatenate each row to a string then print the row:

for row in grid:
    the_row = ''
    for i in row:
        the_row += i
    print(the_row)
\$\endgroup\$
1
  • \$\begingroup\$ You need zip because the data is sideways. If you try this way the image will be on its side. \$\endgroup\$ Jun 13, 2023 at 18:40

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.