List length check not working in Sudoku checker
<p>I want to write some Python code to check that whether a matrix accords with the rule of Sudoku. My code is presented below:</p>

<pre><code>correct = [[1,2,3],
           [2,3,1],
           [3,1,2]]

incorrect = [[1,2,3,4],
             [2,3,1,3],
             [3,1,2,3],
             [4,4,4,4]]

incorrect2 = [[1,2,3,4],
             [2,3,1,4],
             [4,1,2,3],
             [3,4,1,2]]

incorrect3 = [[1,2,3,4,5],
              [2,3,1,5,6],
              [4,5,2,1,3],
              [3,4,5,2,1],
              [5,6,4,3,2]]

incorrect4 = [['a','b','c'],
              ['b','c','a'],
              ['c','a','b']]

incorrect5 = [ [1, 1.5],
               [1.5, 1]]

def check_sudoku(matrix):
    n = len(matrix)
    # check each row
    i, j = 0, 0
    while i &lt; n:
        checked = []
        while j &lt; n:
            if matrix[i][j] not in checked:
                checked.append(matrix[i][j])
            j += 1
        if len(checked) &lt; n:
            return False
        i += 1
    # check each column
    i, j = 0, 0
    while i &lt; n:
        checked = []
        while j &lt; n:
            if matrix[j][i] not in checked:
                len(checked)
                checked.append(matrix[j][i])
            j += 1
        if len(checked) &lt; n:
            return False
        i += 1

    return True

# the output should look like this:
print(check_sudoku(incorrect))
#&gt;&gt;&gt; False

print(check_sudoku(correct))
#&gt;&gt;&gt; True

print(check_sudoku(incorrect2))
#&gt;&gt;&gt; False

print(check_sudoku(incorrect3))
#&gt;&gt;&gt; False

print(check_sudoku(incorrect4))
#&gt;&gt;&gt; False

print(check_sudoku(incorrect5))
#&gt;&gt;&gt; False
</code></pre>

<p>But here's a weird problem in the if statement. After the two inner while loops, the statement "len(checked)" evaluates to 0 which should not be like that. I don't know what happened.</p>

<p>The main problem with your code is that you don't reset <code>j</code> to zero at the end of the inner loops. So when you try to check the second row (and subsequent rows) the <code>j</code> values are too big. The same problem occurs when you're testing the columns.</p>

<p>However, there are other problems with this logic, eg <code>[5,6,4,3,2]</code> tests as ok because it has 5 unique elements, but they aren't the right elements, they should be some permutation of <code>[1,2,3,4,5]</code>. Similarly, the matrix of strings and the matrix containing 1.5 are treated as valid instead of invalid.</p>

<p>But anyway, here's a repaired version that fixes the <code>j</code> initialization issue mentioned earlier.</p>

<pre><code>grids = [
    [[1,2,3],
    [2,3,1],
    [3,1,2]],

    [[1,2,3,4],
    [2,3,1,3],
    [3,1,2,3],
    [4,4,4,4]],

    [[1,2,3,4],
    [2,3,1,4],
    [4,1,2,3],
    [3,4,1,2]],

    [[1,2,3,4,5],
    [2,3,1,5,6],
    [4,5,2,1,3],
    [3,4,5,2,1],
    [5,6,4,3,2]],

    [['a','b','c'],
    ['b','c','a'],
    ['c','a','b']],

    [[1, 1.5],
    [1.5, 1]],
]

def check_sudoku(matrix):
    n = len(matrix)
    # check each row
    i = 0
    while i &lt; n:
        checked = []
        j = 0
        while j &lt; n:
            if matrix[i][j] not in checked:
                checked.append(matrix[i][j])
            j += 1
        if len(checked) &lt; n:
            return False
        i += 1
    # check each column
    i = 0
    while i &lt; n:
        checked = []
        j = 0
        while j &lt; n:
            if matrix[j][i] not in checked:
                checked.append(matrix[j][i])
            j += 1
        if len(checked) &lt; n:
            return False
        i += 1

    return True

for g in grids:
    for row in g:
        print(row)
    print(check_sudoku(g), end='\n\n')
</code></pre>

<p><strong>output</strong></p>

<pre><code>[1, 2, 3]
[2, 3, 1]
[3, 1, 2]
True

[1, 2, 3, 4]
[2, 3, 1, 3]
[3, 1, 2, 3]
[4, 4, 4, 4]
False

[1, 2, 3, 4]
[2, 3, 1, 4]
[4, 1, 2, 3]
[3, 4, 1, 2]
False

[1, 2, 3, 4, 5]
[2, 3, 1, 5, 6]
[4, 5, 2, 1, 3]
[3, 4, 5, 2, 1]
[5, 6, 4, 3, 2]
True

['a', 'b', 'c']
['b', 'c', 'a']
['c', 'a', 'b']
True

[1, 1.5]
[1.5, 1]
True
</code></pre>

<hr>

<p>Here's an alternative strategy which is more compact, and (potentially) faster because it uses Python's fast <code>all</code> function in conjunction with sets to do the testing. This version <em>only</em> considers a matrix to be valid if it contains the integers from 1 to <em>n</em>, where <em>n</em> is the size of the matrix.</p>

<pre><code>grids = [
    [[1,2,3],
    [2,3,1],
    [3,1,2]],

    [[1,2,3,4],
    [2,3,1,3],
    [3,1,2,3],
    [4,4,4,4]],

    [[1,2,3,4],
    [2,3,1,4],
    [4,1,2,3],
    [3,4,1,2]],

    [[1,2,3,4,5],
    [2,3,1,5,6],
    [4,5,2,1,3],
    [3,4,5,2,1],
    [5,6,4,3,2]],

    [['a','b','c'],
    ['b','c','a'],
    ['c','a','b']],

    [[1, 1.5],
    [1.5, 1]],
]

def check_sudoku(matrix):
    full = set(range(1, len(matrix) + 1))
    return (all(set(row) == full for row in matrix)
        and all(set(row) == full for row in zip(*matrix)))

for g in grids:
    for row in g:
        print(row)
    print(check_sudoku(g), end='\n\n')
</code></pre>

<p><strong>output</strong></p>

<pre><code>[1, 2, 3]
[2, 3, 1]
[3, 1, 2]
True

[1, 2, 3, 4]
[2, 3, 1, 3]
[3, 1, 2, 3]
[4, 4, 4, 4]
False

[1, 2, 3, 4]
[2, 3, 1, 4]
[4, 1, 2, 3]
[3, 4, 1, 2]
False

[1, 2, 3, 4, 5]
[2, 3, 1, 5, 6]
[4, 5, 2, 1, 3]
[3, 4, 5, 2, 1]
[5, 6, 4, 3, 2]
False

['a', 'b', 'c']
['b', 'c', 'a']
['c', 'a', 'b']
False

[1, 1.5]
[1.5, 1]
False
</code></pre>

<p>This part: </p>

<pre><code>all(set(row) == full for row in zip(*matrix))
</code></pre>

<p>verifies that the columns are valid because <code>zip(*matrix)</code> essentially creates a transposed version of <code>matrix</code>.</p>

<p>The <code>all</code> function is quite efficient, and it stops testing as soon as it encounters a false-ish result. On a similar note, the <code>and</code> operator short-circuits, which means that the columns aren't checked if the rows aren't valid.</p>

python