Trouble simplifying repetitive - multiple if elif statements and multiple loops in a function in python

244 views Asked by At

I am very new to Python.

I am a firm believer of simple, concise and efficient algorithmic design as well as coding style. As I am learning Python, I realize that Python does a lot of things behind the scene so that the language itself is super friendly to programmers. This is nice but I wanted to learn deeply about what optimizations I can do or keep a habit of when coding. And today I ran into trouble simplify my code.

The following function is used to create empty spots on a sudoku board based on difficulty level that is chosen.

Here is my code:

class normalSudoku(Board):
    def __init__(self,difficulties):
        super.__init__()
        self.Create_Empty_Entries(difficulties)


    def Create_Empty_Entries(self,difficulties):
        numbers = list(range(0,9))
        if difficulties == "Easy":
            for x in range(25):
                a,b = choice(numbers),choice(numbers)
                if self.sudoku[a][b] != None:
                    self.sudoku[a][b] = None
                    self.holes += 1
                self.holes += 1
            return None

        elif difficulties == "Medium":
            for x in range(35):
                a,b = choice(numbers),choice(numbers)
                if self.sudoku[a][b] != None:
                    self.sudoku[a][b] = None
                    self.holes += 1
            return None

        elif difficulties == "Hard":
            for x in range(45):
                a,b = choice(numbers),choice(numbers)
                if self.sudoku[a][b] != None:
                    self.sudoku[a][b] = None
                    self.holes += 1
            return None

        else:
            for x in range(65):
                a,b = choice(numbers),choice(numbers)
                if self.sudoku[a][b] != None:
                    self.sudoku[a][b] = None
                    self.holes += 1
            return None

As you can see it is very repetitive. Any idea on simplifying it or a more efficient coding style will be appreciated.

Also, is there a better way of initializing a class in python rather than calling __init__() in terms of performance and memory usage? Just like in C++ there is initialization list where it is cleaner and faster.

Please feel free to point out the mistakes I have made. Any advice will be greatly appreciated. Thanks

3

There are 3 answers

3
MattWBP On BEST ANSWER

Since the only thing that is changing is the range of numbers being chosen from, I'd recommend creating a dict where difficulty maps to that number then using it in a single function that sets the numbers.

class normalSudoku(Board):
    def __init__(self,difficulties):
        super.__init__()
        self.Create_Empty_Entries(difficulties)


    def Create_Empty_Entries(self,difficulties):
        numbers = list(range(0,9))
        difficulty_values = {'Easy':25,'Medium':35, 'Hard':45, 'Default':65}

        # check the difficulty level exists in the dict. 
        # If it does, use that value, if it doesn't then use the default value
           difficulty = difficulty_values.get(difficulties, difficulty_values['Default'])

            # now use that difficulty to set the numbers once.
            for x in range(difficulty):
            a,b = choice(numbers),choice(numbers)
            if self.sudoku[a][b] != None:
                self.sudoku[a][b] = None
                self.holes += 1
            self.holes += 1
    return None
1
Meow On

You could add a check method to you class:

# add this to the class body
def auto_increment(self, a, b):
    if self.sudoku[a][b] != None:
       self.sudoku[a][b] = None
       self.holes += 1
    self.holes += 1
    return

Then you can just pass you parameters to your method using:

self.auto_increment(choices(number), choices(number))

slots are an effective way to reduce memory usage Usage of __slots__?

2
tavnab On

One option is to move the parameters from code to data, and then operate on the data:

# You could source these two dicts from elsewhere, like a JSON/YAML/config file
difficulties = {
  Easy: {
    size: 25
  },
  Medium: {
    size: 35
  },
  Hard: {
    size: 45
  }
}

defaultDifficulty = {
  size: 65
}

# ...

def Create_Empty_Entries(self, difficultyName):
  if difficultyName in difficulties:
    difficulty = difficulties[difficultyName]
  else:
    difficulty = defaultDifficulty

  numbers = list(range(0,9))
  for x in range(difficulty.size):
    a,b = choice(numbers),choice(numbers)
    if self.sudoku[a][b] != None:
      self.sudoku[a][b] = None
      self.holes += 1