Given a Sudoku data structure with size `NxN, N > 0 and √N == integer`, write a method to validate if it has been filled out correctly.


The data structure is a multi-dimensional Array, i.e:
```
[
  [7,8,4,  1,5,9,  3,2,6],
  [5,3,9,  6,7,2,  8,4,1],
  [6,1,2,  4,3,8,  7,5,9],
  
  [9,2,8,  7,1,5,  4,6,3],
  [3,5,7,  8,4,6,  1,9,2],
  [4,6,1,  9,2,3,  5,8,7],
  
  [8,7,6,  3,9,4,  2,1,5],
  [2,4,3,  5,6,1,  9,7,8],
  [1,9,5,  2,8,7,  6,3,4]
]
```

**Rules for validation**

- Data structure dimension: `NxN` where `N > 0` and `√N == integer`
- Rows may only contain integers: `1..N (N included)`
- Columns may only contain integers: `1..N (N included)`
- *'Little squares'* (`3x3` in example above) may also only contain integers: `1..N (N included)`

Difficulty: interview

Starter code:

def __init__(self, board):
	

Solutions:
import math

class Sudoku(object):
    def __init__(self, board):
        self.board = board
        
    def is_valid(self):
        if not isinstance(self.board, list):
            return False
        n = len(self.board)
        rootN = int(round(math.sqrt(n)))
        if rootN * rootN != n:
            return False
        isValidRow = lambda r : (isinstance(r, list) and
                                 len(r) == n and
                                 all([type(x) == int for x in r]))
        if not all(map(isValidRow, self.board)):
            return False
        oneToN = set(range(1, n + 1))
        isOneToN = lambda l : set(l) == oneToN
        tranpose = [[self.board[j][i] for i in range(n)] for j in range(n)]
        squares = [[self.board[p+x][q+y] for x in range(rootN) 
                                         for y in range(rootN)] 
                                         for p in range(0, n, rootN)
                                         for q in range(0, n, rootN)] 
        return (all(map(isOneToN, self.board)) and
                all(map(isOneToN, tranpose)) and
                all(map(isOneToN, squares)))


import numpy as np
class Sudoku(object):

    def __init__(self, theArray):
        self.grid = np.array(theArray)
        self.listgrid = theArray
        
        self.N = len(theArray)
        self.M = len(theArray[0])
        
    def has_valid_size(self):
        
        if isinstance(self.listgrid[0][0], bool): return False
        if self.grid.shape == (1,1):
            return True
        for i in self.listgrid:
            if len(i) != self.N: return False
        return True

    
    #your code here
    def is_valid(self):   
        if not self.has_valid_size(): 
            return False
        
        seqs2check = [self.getRowsIterator(), self.getColsIterator(), self.getSquaresIterator()]
        for it in seqs2check:
            for seq in it:
                if self.checkSeq(seq) == False:
                    return False
        return True            
                
    def getRowsIterator(self):
        for i in range(self.N):
            yield self.grid[i,:]
            
    def getColsIterator(self):
        for i in range(self.N):
            yield self.grid[:,i]
            
    def getSquaresIterator(self):
        squareSize = int(np.sqrt(self.N))    
        for i in range(squareSize):
            for j in range(squareSize):
                ix1 = i*squareSize
                ix2 = j*squareSize
                yield self.grid[ix1:ix1+squareSize, ix2:ix2+squareSize].flatten()
        
    def checkSeq(self, seq):
        return sorted(seq) == list(range(1,self.N+1))


import math

class Sudoku(object):
    def __init__(self, board):
        self.board = board
        self.size = len(board)

    @staticmethod
    def reduce_logic(seq):
        return reduce(lambda x, y: x and y, seq)

    def is_square(self):
        return self.reduce_logic(map(lambda x: len(x) == self.size, self.board))

    def check_number(self):
        return self.reduce_logic(map(lambda x: 0 < x <= self.size and type(x) == type(1),
                                     reduce(lambda x, y: x + y, self.board)))

    def check_seq(self, seq):
        return self.reduce_logic(map(lambda x: len(set(x)) == self.size, seq))

    def check_rows(self):
        return self.check_seq(self.board)

    def check_cols(self):
        cols = [map(lambda x: x[i], self.board) for i in range(self.size)]
        return self.check_seq(cols)

    def check_little_squares(self):
        sq = int(math.sqrt(self.size))
        squares = [reduce(lambda x, y: x + y, map(lambda x: x[i:(i + sq)], self.board[j:(j + sq)]))
                   for j in range(0, self.size, sq)
                   for i in range(0, self.size, sq)]
        return self.check_seq(squares)

    def is_valid(self):
        if (self.is_square() and
                self.check_number() and
                self.check_rows() and
                self.check_cols() and
                self.check_little_squares()):
            return True
        else:
            return False

from itertools import chain
import math

class Sudoku(object):

    def __init__(self, data):
        self.grip = data
        self.len = len(data)
        self.valid = (self.len == 1 and data != [[1]]) or not all(( len(e) == self.len for e in data )) or all(type(x)!=int for e in data for x in e )
        self.box = int(math.sqrt(self.len))
    
    def resp(self):
        self.grip = list( zip( *[ list( zip( *[iter(e)]*self.box)) for e in self.grip][::-1] ))
        return [list(chain(*list( zip( *[iter(e)]*self.box))[i]))  for e in self.grip for i in range(len(self.grip)//self.box)]
                 
    def is_valid(self): 
        return not self.valid and all(( len(set(e)) == self.len  for e in self.resp() ))

class Sudoku(object):
    def __init__(self, grid):
        self.grid = grid
        self.dim = len(grid)
        self.boxsize = int(self.dim ** 0.5)
        self.nums = set(range(1, self.dim + 1))
        
    def row_valid(self, row):
        return self.nums == set(self.grid[row])
        
    def col_valid(self, col):
        return self.nums == set(self.grid[row][col] for row in range(self.dim))
        
    def box_valid(self, box):
        box_row, box_col = divmod(box, self.boxsize)
        box_row, box_col = box_row * self.boxsize, box_col * self.boxsize
        return self.nums == set(self.grid[row][col]
            for row in range(box_row, box_row + self.boxsize)
            for col in range(box_col, box_col + self.boxsize))
        
    def is_valid(self):
        if any(len(row) != self.dim for row in self.grid):
            return False
        if any(any(not isinstance(i, int) or i is True or i is False
            for i in row)
            for row in self.grid):
            return False
        return (all(self.row_valid(row) for row in range(self.dim)) and
            all(self.col_valid(col) for col in range(self.dim)) and
            all(self.box_valid(box) for box in range(self.dim)))

import math

class Sudoku(object):
    def __init__(self, board):
        self.board = board
        
    def is_valid(self):
        if not isinstance(self.board, list):
            return False
        n = len(self.board)
        rootN = int(round(math.sqrt(n)))
        if rootN * rootN != n:
            return False
        isValidRow = lambda r : (isinstance(r, list) and
                                 len(r) == n and
                                 all(map(lambda x : type(x) == int, r)))
        if not all(map(isValidRow, self.board)):
            return False
        oneToN = set(range(1, n + 1))
        isOneToN = lambda l : set(l) == oneToN
        tranpose = [[self.board[i][j] for i in range(n)] for j in range(n)]
        squares = [[self.board[p+x][q+y] for x in range(rootN) 
                                         for y in range(rootN)] 
                                         for p in range(0, n, rootN)
                                         for q in range(0, n, rootN)] 
        return (all(map(isOneToN, self.board)) and
                all(map(isOneToN, tranpose)) and
                all(map(isOneToN, squares)))

class Sudoku(object):
    def __init__(self, board):
        self.board = board
    def is_valid(self):
        n = int(len(self.board)**0.5)
        if not all(len(row) == n*n and all(not isinstance(cell, bool) for cell in row) for row in self.board):
            return False
        r, rr = range(n), range(0, n*n, n)
        blocks = [[self.board[x+a][y+b] for a in r for b in r] for x in rr for y in rr]
        return not [x for x in self.board + list(zip(*self.board)) + blocks if set(x) != set(range(1, n*n + 1))]


from itertools import chain


class Sudoku(object):

    def __init__(self, data):
        self.data = data
        self.n = len(data)
        self.nums = set(range(1, self.n+1))

    def is_valid(self):
        return (
            all(len(row) == self.n for row in self.data)
            and self.are_all_ints()
            and self.are_row_nums_valid()
            and self.are_col_nums_valid()
            and self.are_squares_valid()
        )

    def are_all_ints(self):
        return all(
            isinstance(x, int) and not isinstance(x, bool)
            for row in self.data for x in row
        )

    def are_row_nums_valid(self):
        return all(set(row) == self.nums for row in self.data)
    
    def are_col_nums_valid(self):
        return all(set(row) == self.nums for row in zip(*self.data))
        
    def are_squares_valid(self):
        sq = int(self.n ** 0.5)
        return all(
            set(chain.from_iterable(row[j:j+sq] for row in self.data[i:i+sq])) == self.nums
            for i in range(0, self.n, sq)
            for j in range(0, self.n, sq)
        )

import math
    
class Sudoku(object):        
    def __init__(self, board):
        self.board = board
        self.size = len(board)
        self.lil_size = math.sqrt(self.size)
    
    def is_valid(self):    
        # dimensions must be the same
        if not all(len(r) == self.size for r in self.rows()):
            return False

        # size must be a perfect square
        if not self.lil_size.is_integer():
            return False

        # corner case (True == 1 in python)
        if self.board[0][0] is True:
            return False

        # groups must fill the range
        numbers = range(1, self.size + 1)
        groups = self.rows() + self.columns() + self.lil_squares()        
        for group in groups:
            if sorted(group) != numbers:
                return False
      
        return True       
    
    def rows(self):
        return self.board
        
    def columns(self):
        return zip(*self.rows())
    
    def lil_squares(self):
        result = []
        size = int(self.lil_size)
        for i in range(size):
            for j in range(size):            
                square = []
                for k in range(size):
                    for l in range(size):
                        square.append(self.board[i * size + k][j * size + l])
                result.append(square)                
        return result

from itertools import chain

class Sudoku(object):

    def __init__(self, grid):
        self.grid = grid
        self.size = len(grid)
        self.good_zone = set(range(1, self.size + 1))
    
    def __iter__(self):
        """Iterate over each row, column and square of the sudoku"""
        rows = self.grid
        cols = zip(*rows)
        square_size = int(self.size ** 0.5)
        squares = [sum((rows[y+i][x:x+square_size]
                        for i in range(square_size)), [])
                   for y in range(0, self.size, square_size)
                   for x in range(0, self.size, square_size)]
        return chain(rows, cols, squares)
    
    def valid_data_types(self):
        """Check data types"""
        return all(type(num) == int for num in chain(*self.grid))
    
    def zone_is_valid(self, zone):
        """Check if a zone contain every numbers"""
        return set(zone) == self.good_zone
    
    def is_valid(self):
        """Is the sudoku solved"""
        if not self.valid_data_types(): return False
        return all(self.zone_is_valid(zone) for zone in self)