Can I use "zip ()" with step parameter in Python?

I would like to extract a very specific piece of a 2D array in Python using a method zip()

(and avoid the messy loop logic). I would like to use zip to achieve something like this:

>>> sub_matrix = list(zip([*grid[0:3]]*3))

# Desired output example (Option 1)
[".","4",".", ".",".","4",".",".","."]

# Desired output example (Option 2)
[[".","4","."],  
[".",".","4"],
[".",".","."]]

      

I am working with the 2D Array given below in Python on an interview practice problem.

grid = [[".","4",".",".",".",".",".",".","."],
    [".",".","4",".",".",".",".",".","."],
    [".",".",".","1",".",".","7",".","."],
    [".",".",".",".",".",".",".",".","."],
    [".",".",".","3",".",".",".","6","."],
    [".",".",".",".",".","6",".","9","."],
    [".",".",".",".","1",".",".",".","."],
    [".",".",".",".",".",".","2",".","."],
    [".",".",".","8",".",".",".",".","."]]

      

Part of solving the problem involves ensuring that every 3 x 3 "area" in a Sudoku game contains legal meanings. I would like to use zip()

to quickly extract the 3 x 3 part of a matrix. For example, the top left area will cause the tests to fail because it contains four times.

enter image description here

I know I can multiply the grid to get the first three lines like this:

    >>> sub_grid = grid[0:3]
    >>> print(sub_grid)
    [['.', '4', '.', '.', '.', '.', '.', '.', '.'], 
    ['.', '.', '4', '.', '.', '.', '.', '.', '.'], 
    ['.', '.', '.', '1', '.', '.', '7', '.', '.']]

      

I changed the print a bit to make it obvious, but at this point I would like to archive the three arrays using a "step" of 3, so that each new array will cover 3 values ​​from each array before moving on to the next.

There is no snippetzip

in the Python3 docs of how I think it can be done, but I can't seem to get the output I want.

Left-to-right iteration order is guaranteed. This makes the idiom possible for clustering a series of data into n-length using zip(*[iter(s)]*n)

.

(For posterity, the question from CodeFights will be hidden until unlocked )

Any help is appreciated. Thank you.

+3


source to share


3 answers


No zip code but [row[:3] for row in grid[:3]]



+3


source


zip

does not support going through nested structures this way. Another alternative to the other answer is using map

and retrieving these fragments.

from operator import itemgetter
list(map(itemgetter(0, 1, 2), grid[0:3]))

      

or, if you like:

list(map(lambda x: x[0:3], grid[0:3]))

      



If you are using python2 you can remove the extra list(...)

.

As for the way to use it and why, take a look at this thread on SO.

Output:

[('.', '4', '.'), ('.', '.', '4'), ('.', '.', '.')]

      

+2


source


TL; DR

To make blocks work with a single layer:

[reduce(lambda a, b: a+b, item) for l in [zip(*row) for row in zip(*[iter([zip(*[iter(row)]*3) for row in grid])]*3)] for item in l]

      

Step by step explanation

First, let's see how to use zip

:

chunks = [zip(*[iter(row)]*3) for row in grid]

[
    [('.', '4', '.'), ('.', '.', '.'), ('.', '.', '.')],
    [('.', '.', '4'), ('.', '.', '.'), ('.', '.', '.')],
    [('.', '.', '.'), ('1', '.', '.'), ('7', '.', '.')],
    [('.', '.', '.'), ('.', '.', '.'), ('.', '.', '.')],
    [('.', '.', '.'), ('3', '.', '.'), ('.', '6', '.')],
    [('.', '.', '.'), ('.', '.', '6'), ('.', '9', '.')],
    [('.', '.', '.'), ('.', '1', '.'), ('.', '.', '.')],
    [('.', '.', '.'), ('.', '.', '.'), ('2', '.', '.')],
    [('.', '.', '.'), ('8', '.', '.'), ('.', '.', '.')]
]

      

You can see how each line is divided into chunks of size three. The lines also need to be split, so we run:

blocks = zip(*[iter(chunks)]*3)

[
    (
        [('.', '4', '.'), ('.', '.', '.'), ('.', '.', '.')],
        [('.', '.', '4'), ('.', '.', '.'), ('.', '.', '.')],
        [('.', '.', '.'), ('1', '.', '.'), ('7', '.', '.')]
    ), (
        [('.', '.', '.'), ('.', '.', '.'), ('.', '.', '.')],
        [('.', '.', '.'), ('3', '.', '.'), ('.', '6', '.')],
        [('.', '.', '.'), ('.', '.', '6'), ('.', '9', '.')]
    ), (
        [('.', '.', '.'), ('.', '1', '.'), ('.', '.', '.')],
        [('.', '.', '.'), ('.', '.', '.'), ('2', '.', '.')],
        [('.', '.', '.'), ('8', '.', '.'), ('.', '.', '.')]
    )
]

      

This gives us blocks. For extraction, it makes sense to transfer them first:

transposed_blocks = [zip(*row) for row in blocks]

[
    [
        (('.', '4', '.'), ('.', '.', '4'), ('.', '.', '.')),
        (('.', '.', '.'), ('.', '.', '.'), ('1', '.', '.')),
        (('.', '.', '.'), ('.', '.', '.'), ('7', '.', '.'))
    ], [
        (('.', '.', '.'), ('.', '.', '.'), ('.', '.', '.')),
        (('.', '.', '.'), ('3', '.', '.'), ('.', '.', '6')),
        (('.', '.', '.'), ('.', '6', '.'), ('.', '9', '.'))
    ], [
        (('.', '.', '.'), ('.', '.', '.'), ('.', '.', '.')),
        (('.', '1', '.'), ('.', '.', '.'), ('8', '.', '.')),
        (('.', '.', '.'), ('2', '.', '.'), ('.', '.', '.'))
    ]
]

      

You can see how each block is now on a separate line. The last step is to concatenate each line into one list:

blocks_as_list = [reduce(lambda a, b: a+b, item)
                  for l in transposed_blocks for item in l]

[
    ('.', '4', '.', '.', '.', '4', '.', '.', '.'),
    ('.', '.', '.', '.', '.', '.', '1', '.', '.'),
    ('.', '.', '.', '.', '.', '.', '7', '.', '.'),
    ('.', '.', '.', '.', '.', '.', '.', '.', '.'),
    ('.', '.', '.', '3', '.', '.', '.', '.', '6'),
    ('.', '.', '.', '.', '6', '.', '.', '9', '.'),
    ('.', '.', '.', '.', '.', '.', '.', '.', '.'),
    ('.', '1', '.', '.', '.', '.', '8', '.', '.'),
    ('.', '.', '.', '2', '.', '.', '.', '.', '.')
]

      

And we will get a list of all blocks. Now you can check them for Sudoku rules.

+1


source







All Articles