Valid Sudoku in Swift This is my solution to LeetCode – Valid Sudoku in Swift.



class Solution {
    func isValidSudoku(_ board: [[Character]]) -&gt; Bool {
        let count = board.count


        var set = Set&lt;Character&gt;()
        for i in 0..&lt;count{

            //  firstly
            set = Set(board[i])

            var num = board[i].reduce(0 , {(result : Int, char : Character)
                in
                var cent = 0
                if String(char) == "."{
                    cent = 1
                }
                return result + cent
            })

            if num &gt; 0 , count - num != set.count - 1{
                return false
            }
            else if num == 0, set.count != count{
                return false
            }


            // secondly

            set = Set(board.reduce([Character]() , { resultArray, chars in
                return resultArray + [chars[i]]
            }))

            num = board.reduce(0 , {(result : Int, chars : [Character])
                in
                var cent = 0
                if String(chars[i]) == "."{
                    cent = 1
                }
                return result + cent
            })

            if num &gt; 0 , count - num != set.count - 1{
                return false
            }
            else if num == 0, set.count != count{
                return false
            }



            // thirdly
            let characters = board.flatMap{
                return $0
            }


            let fisrtMiddle = ( i/3 ) * 27 + ( i % 3 ) * 3 + 1
            let secondMiddle = fisrtMiddle + 9
            let thirdMiddle = fisrtMiddle + 18
            let arrayThree = [characters[fisrtMiddle - 1], characters[fisrtMiddle], characters[fisrtMiddle + 1],
                                                       characters[secondMiddle - 1], characters[secondMiddle], characters[secondMiddle + 1],
                                                                                        characters[thirdMiddle - 1], characters[thirdMiddle], characters[thirdMiddle + 1]]
            set = Set(arrayThree)
            num = arrayThree.reduce(0 , {(result : Int, char : Character)
                in
                var cent = 0
                if String(char) == "."{
                    cent = 1
                }
                return result + cent
            })

            if num &gt; 0 , count - num != set.count - 1{
                return false
            }
            else if num == 0, set.count != count{
                return false
            }
        }


        return true
    }
}


How can I make it shorter in syntax and keep intuitive, like the following Python code?

def isValidSudoku(self, board):
    seen = sum(([(c, i), (j, c), (i/3, j/3, c)]
                for i, row in enumerate(board)
                for j, c in enumerate(row)
                if c != '.'), [])
    return len(seen) == len(set(seen))


The Python code is very Pythonic and short.

How to use Swift syntax power to make my code shorter?

I think Functional is a good choice. RxSwift is welcomed.
Naming

Some variable names should be more descriptive: 


What does set contain?
What does num count?
What is cent or arrayThree?


Simplifications

if String(char) == "." can be shorted to if char == ".", the conversion to
a string is not needed because "." can be both a string literal and a
character literal.

In 

var num = board[i].reduce(0 , {(result : Int, char : Character)
    in
    var cent = 0
    if String(char) == "."{
        cent = 1
    }
    return result + cent
})


the closure can be shortened to

var num = board[i].reduce(0 , {(result, char) in
    char == "." ? result + 1 : result
})


without the need for a temporary variable.

In

set = Set(board.reduce([Character]() , { resultArray, chars in
    return resultArray + [chars[i]]
}))


an array is created with the elements in column #i, and put into a set. That can be simplified to

let column = board.map { $0[i]} // Column #i
set = Set(column)


and column can then also be used in the following count of empty fields.

The creation of an array of all entries of a block can be simplified using
array slices:

let firstRow = 3 * (i / 3)
let firstCol = 3 * (i % 3)
let block = board[firstRow..&lt;firstRow+3].flatMap { $0[firstCol..&lt;firstCol+3]}


Generally, the check for duplicate digits in a row/column/block can
be simplified if you filter out empty fields before creating the set,
that makes counting the empty fields obsolete.

Comments

The comments

// firstly
// secondly
// thirdly


are not really helpful. 

Putting it together

Summarizing the above suggestions so far, the code could look like this:

class Solution {
    func isValidSudoku(_ board: [[Character]]) -&gt; Bool {

        for i in 0..&lt;9 {
            // Check digits in row #i:
            let rowDigits = board[i].filter { $0 != "." }
            if rowDigits.count != Set(rowDigits).count {
                return false
            }

            // Check digits in column #i:
            let colDigits = board.map { $0[i] }.filter { $0 != "." }
            if colDigits.count != Set(colDigits).count {
                return false
            }

            // Check digits in block #i:
            let firstRow = 3 * (i / 3)
            let firstCol = 3 * (i % 3)
            let blockDigits = board[firstRow..&lt;firstRow+3].flatMap { $0[firstCol..&lt;firstCol+3]}
                .filter { $0 != "." }
            if blockDigits.count != Set(blockDigits).count {
                return false
            }       
        }

        return true
    }
}


An alternative approach

The Python solution can not be translated directly to Swift, one reason is
that tuples are not Hashable and therefore cannot be put into a set.
Also inhomogeneous collections are better avoided in Swift.

But we can enumerate the board in a similar fashion, and put each element
into a set corresponding to its row, column, and block. The return value
from the insert statement already indicates if an identical element was
already present.

That leads to the following implementation:

class Solution {
    func isValidSudoku(_ board: [[Character]]) -&gt; Bool {
        var rowSets = Array(repeating: Set&lt;Character&gt;(), count: 9)
        var colSets = Array(repeating: Set&lt;Character&gt;(), count: 9)
        var blockSets = Array(repeating: Set&lt;Character&gt;(), count: 9)

        for (i, row) in board.enumerated() {
            for (j, char) in row.enumerated() where char != "." {
                if !rowSets[i].insert(char).inserted {
                    return false
                }
                if !colSets[j].insert(char).inserted {
                    return false
                }
                let block = (i / 3) + 3 * (j / 3)
                if !blockSets[block].insert(char).inserted {
                    return false
                }
            }
        }

        return true
    }
}


I haven't checked which one is more efficient, I leave that task to you :)