Saving a value, removing it and then running again with the rest of a list - python-3.x

Problem Description
I am firstly I am having a list of values like:
(1,2,3,1,3,2,2,2,1)
What I want to achieve is :
Find the most common one (working).
Delete it from the list (working).
Repeat the same thing for the remaining values in the list.
For instance
Taking this Tuple:
(1,2,3,1,3,2,2,2,1)
Store that 2 is the most common int, then
(1,3,3,1,1,)
Store that 1 is the second most common int, then
(3,3)
Store that 2 is the third most common int, then
My source Code
NOTE lets say that self.final_votes would be (1,2,3,1,3,2,2,2,1)
def erase_common(self):
possitions = []
counter = 0
common = self.final_votes[0]
for i in self.final_votes:
cand_freq = self.final_votes.count(i)
if(cand_freq> counter):
counter = cand_freq
common = i
possitions.append(common)
while common in self.final_votes:
self.final_votes.remove(common)
this is the whole code
class voting_system:
def __init__(self):
#self.tutor_group = self.get_tutor_group()
self.stud_num = self.get_stud_num()
self.cand_num = self.get_cand_num()
self.cand_name = self.get_cand_name()
self.final_votes = self.ind_votes()
self.erase_common()
# def get_tutor_group(self):
# tutor_groups = ("7A","7B","7C","7D","7E","7F","8A","8B","8C","8D","8E","8F","9A","9B","9C","9D","9E","9E",
# "9F","10A","10B","10C","10D","10E","10F","11A","11B","11C","11D","11E","11F")
#
# flag = True
# while flag == True:
# try:
# self.tutor_group = input("please enter the tutor group: ")
# if self.tutor_group not in tutor_groups:
# raise ValueError("Tutor group entred doesn't exist")
# except ValueError as error:
# print(error)
# flag = True
#
# else:
# flag = False
# return self.tutor_group
def get_stud_num(self):
# flag = True
# while flag == True:
# try:
# self.stud_num = int(input("Please enter number of students: "))
# if self.stud_num<0 or self.stud_num>35:
# raise ValueError("NUMBER OF STUDENTS INVALID")
# except ValueError as error:
# print(error)
# flag = True
#
# else:
# flag = False
self.stud_num = 7
return self.stud_num
def get_cand_num(self):
# flag = True
# while flag == True:
# try:
# self.cand_num = int(input("Please enter number of candidates: "))
# if self.cand_num>4:
# raise ValueError("NUMBER OF CANDIDATES INVALID")
# except ValueError as error:
# print(error)
# flag = True
#
# else:
# flag = False
self.cand_num = 3
return self.cand_num
def get_cand_name(self):
self.cand_name = []
for i in range(self.cand_num):
candidate = input("Enter candidate name: ")
self.cand_name.append(candidate)
return self.cand_name
def print_cands(self):
for i in range(len(self.cand_name)):
print(i+1, " : ", self.cand_name[i])
def ind_votes(self):
self.final_votes = []
self.print_cands()
abs_vote = 0
flag = True
while flag == True:
try:
for i in range(self.stud_num):
vote = input("To vote type 'V' and the candidates number, to abstent type 'A': ")
if vote.isalpha() == True:
abs_vote +=1
else:
self.final_votes.append(vote[1])
if vote[1] > str(self.cand_num):
raise ValueError("VOTED CANDIDATE NONEXISTENT")
except ValueError as error:
print(error)
flag = True
else:
flag = False
return self.final_votes
return abs_vote
def erase_common(self):
possitions = []
counter = 0
common = self.final_votes[0]
for i in self.final_votes:
cand_freq = self.final_votes.count(i)
if(cand_freq> counter):
counter = cand_freq
common = i
possitions.append(common)
while common in self.final_votes:
self.final_votes.remove(common)
run = voting_system()
any suggestions would be appreciated:)

Easier and probably the best:
User Python Counter from Collection.
from collections import Counter
final_votes = [1, 2, 3, 1, 3, 2, 2, 2, 1]
def erase_common(votes):
count_votes = Counter(votes)
return count_votes.most_common()
print(erase_common(final_votes)) # [(2, 4), (1, 3), (3, 2)]
votes = erase_common(final_votes)
for idx, votes in enumerate(votes):
print(f'{idx+1}) Vote {votes[0]} Total = {votes[1]}')
OUTPUT
1) Vote 2 Total = 4
2) Vote 1 Total = 3
3) Vote 3 Total = 2
Using groupby
#AlexMartelli has a really good answer regarding find most common element on list --> Find the most common element in a list
So you can implement this by doing this:
from itertools import groupby
final_votes = [1, 2, 3, 1, 3, 2, 2, 2, 1]
def most_common_oneliner(L):
grupped = groupby(sorted(L))
result = {group: len([*scores]) for group, scores in grupped}
final_sorted_votes = []
while result:
max = [(0, 0)]
for score, res in result.items():
if max[0][1] < res:
max[0] = (score, res)
del result[max[0][0]]
final_sorted_votes += max
return final_sorted_votes
result = most_common_oneliner(final_votes)
for idx, votes in enumerate(result):
print(f'{idx+1}) Vote {votes[0]} Total = {votes[1]}')
Documentation
Counter
Counter Implementation
most_common function inplementation
groupby
how-do-i-use-itertools-groupby Stack Overflow
geeksforgeeks.org | python-find-most-frequent-element-in-a-list

Related

Backtracking problem in Knights tour algorithm

**Edit: I managed to find solution for my problem so i put the correct code in place. Everything works perfect now.
I'm trying to complete the last stage of a project in Jetbrains Academy but I can't make my approach to the problem work:
It gives the user the solution for the knights tour in chess if it exists by taking their inputs. I know that there are working solutions out there, but I would like to make it work with the approach I have taken.
I can't make it work. Although, it works fine when the player plays with and I had cut the extra lines.
Example:
Input: A 4x3 board, and 1 3 (column/row)
My implementation gives 2 possible moves [(3, 2), (2, 1)]. It then continues for the possible values of 2 1 and it goes all the way down until it has no other solutions. Then it stops. Those inputs works because they dont require further search in the inside possible valid move. It doesn't check multiple paths that exist at the deeper level.
I don't understand why this happens. Where is the problem in the code?
Initialization of the board (there are extra variables because of the previous steps):
# Write your code here
from copy import deepcopy
import sys
sys.setrecursionlimit(2000)
# With that recursion limit you can test boards up to 40x40 instantly.
# Without this you can test easily up to 30 x 30 any value
# and up to 35x35 any value except edge columns / rows ex 1 4 / 4 1.
class ChessBoard:
def __init__(self, dimensions: str):
self.game_over = False
self.valid_grid = True
self.dimensions = self.board_validation(dimensions.strip().split())
if self.valid_grid:
self.x = self.dimensions[0]
self.y = self.dimensions[1]
self.cell_length = len(str(self.x * self.y)) # Cell format helper for spaces
self.board = [[(x, y) for x in range(1, self.x + 1)] for y in range(self.y, 0, -1)]
self.visual = [["_" * self.cell_length for _ in range(1, self.x + 1)] for _ in range(self.y, 0, -1)]
self.moves_visit = {key: False for i in range(len(self.board)) for key in self.board[i]}
# We need duplicates to reverse the state of the board if we want:
# to continue the game - try other initial move for the valid movements pool
self.board_duplicate = deepcopy(self.board)
self.visual_duplicate = deepcopy(self.visual)
self.moves_visit_duplicate = deepcopy(self.moves_visit)
self.x_boundaries = {i for i in range(1, self.x + 1)}
self.y_boundaries = {i for i in range(1, self.y + 1)}
self.valid_moves = [] # Helper for getting instant valid_moves for the player.
self.is_first_move = True # With that we make it easier to differentiate the first move from other inputs.
self.movements_made = 0 # Move counter direct connection with the AI solution finder and the AI move
self.board_dimensions = self.x * self.y
self.has_solution = False
self.initial_move_for_ai = None
self.first_valid_move = set({})
self.moves_placed = set({}) # Fast comparison to check if the ai_play function will return from recursion
self.total_moves = 0
self.find_solution_mode = False
def set_first(self):
if self.is_first_move:
self.is_first_move = False
def board_validation(self, board_dimensions):
if len(board_dimensions) != 2:
self.valid_grid = False
return False
try:
x = int(board_dimensions[0])
y = int(board_dimensions[1])
if x <= 0 or y <= 0:
self.valid_grid = False
return False
self.valid_grid = True
return x, y
except ValueError:
self.valid_grid = False
return False
def move_validation(self, move_to_validate):
if isinstance(move_to_validate, tuple) and move_to_validate[0] in self.x_boundaries and \
move_to_validate[1] in self.y_boundaries:
return move_to_validate
values = move_to_validate.split()
if len(values) != 2:
return False
try:
column = int(values[0])
row = int(values[1])
movement = (column, row)
if column not in self.x_boundaries or row not in self.y_boundaries:
return False
if not self.is_first_move and self.moves_visit[movement]:
return False
if not self.is_first_move and movement not in self.valid_moves:
return False
return movement
except ValueError:
return False
# Knight movement. X for player - Movement number for AI
def knight_move(self, movement, solution_mode=False):
if self.movements_made == 0:
self.set_first()
movement = self.move_validation(movement)
for m in range(len(self.board)):
if movement in self.board[m]:
index_of_move = self.board[m].index(movement)
if not self.moves_visit[movement]:
if not solution_mode:
self.visual[m][index_of_move] = " " * (self.cell_length - 1) + "X"
else:
move = "" * (self.cell_length - 3) + str(self.movements_made + 1)
self.visual[m][index_of_move] = move.rjust(self.cell_length)
self.possible_moves(movement)
self.movements_made += 1
self.moves_visit[movement] = True
return movement
return False
# Calculating exact moves to chose from. We return index based values based on visual repr
# and also player based values (2, 1), (3, 2) etc.. columns / rows
def move_calculation(self, movement_to_calc):
movement = movement_to_calc
value_to_process = [(-2, -1), (-2, 1), (-1, 2), (1, 2), (2, 1), (2, -1), (-1, -2), (1, -2)]
possible_calculations = [(movement[0] + value_to_process[i][0], movement[1] +
value_to_process[i][1]) for i in range(len(value_to_process))]
final_possible_indexes = [(r, self.board[r].index(j)) for r in range(len(self.board))
for j in possible_calculations if j in self.board[r] and not self.moves_visit[j]]
final_possible_indexes_translation = [self.board[i][j] for i, j in final_possible_indexes]
return final_possible_indexes, final_possible_indexes_translation
# Function that is used to calculate how many moves we have for the valid placements on board
def depth_calc(self, valid_move):
x, y = self.move_calculation(valid_move)
return len(x)
# Similar to move_calculation but this one is used to register primary valid moves for player on board
# And also to check the state of players game and outputting the depth values for the valid moves.
def possible_moves(self, main_move):
try:
moves, moves_translation = self.move_calculation(main_move)
combined_index_translation = set(zip(moves, moves_translation))
except TypeError:
return False
if not self.find_solution_mode:
for i, j in combined_index_translation:
col, row = i[0], i[1]
if not self.moves_visit[j]:
self.visual[col][row] = f'{" " * (self.cell_length - 1)}{self.depth_calc(j) - 1}'
self.valid_moves = moves_translation
print(self.__str__())
self.board_updater()
self.check_end()
return moves_translation
# Board update based on the moves_visit state True/False (if we visited or not)
def board_updater(self):
for i in range(len(self.board)):
for j in range(len(self.board[i])):
move_to_check = self.board[i][j]
if self.moves_visit[move_to_check]:
self.visual[i][j] = f'{" " * (self.cell_length - 1)}*'
else:
self.visual[i][j] = f'{" " * (self.cell_length - 1)}_'
# Getting all primary valid moves to work with
def get_valid_moves(self, from_move):
valid = self.possible_moves(from_move)
if valid:
return valid
else:
return False
# Key function for the ai_play function. It gives us the valid move with the minimum depth.
def lower_move(self, valid_values):
lengths = {i: self.depth_calc(i) for i in valid_values}
min_depth = min(lengths, key=lengths.get)
return min_depth
# Recursive function that is giving us the solution for the inputted move
def ai_play(self, move, pool, n):
if not self.moves_placed:
self.moves_placed.add(move)
if n == 1:
self.first_valid_move.add(self.lower_move(pool))
if len(self.moves_placed) == self.board_dimensions:
self.has_solution = True
return True
if self.total_moves >= self.board_dimensions ** 4:
return False
self.total_moves += 1
if pool:
best_move = self.lower_move(pool)
ai_move = self.knight_move(best_move, solution_mode=True)
self.moves_placed.add(ai_move)
if ai_move:
possible_moves = self.get_valid_moves(ai_move)
if self.ai_play(ai_move, possible_moves, n + 1):
return True
else:
self.ai_play_reset()
first_move = self.knight_reset()
self.moves_placed.add(first_move)
first_pool = self.get_valid_moves(first_move)
self.first_valid_move.add(first_pool[0])
new_pool = set(first_pool).difference(self.first_valid_move)
try:
self.ai_play(first_move, list(new_pool), 1)
except RecursionError:
self.ai_play_reset()
return False
except IndexError:
print("We tested all initial valid moves and failed.\nChoose one cell higher column and try again")
return False
# Resets the important variables of the board. Crucial if ai_play doesn't find a solution with first try.
def ai_play_reset(self):
self.moves_placed.clear()
self.board = deepcopy(self.board_duplicate)
self.visual = deepcopy(self.visual_duplicate)
self.moves_visit = deepcopy(self.moves_visit_duplicate)
self.movements_made = 0
self.has_solution = False
self.first_valid_move.clear()
# Checks the state of the player's game.
def check_end(self):
if not self.valid_moves:
self.game_over = True
if self.movements_made + 1 == self.board_dimensions:
self.has_solution = True
print("What a great tour! Congratulations!")
return False
else:
print(f"No more possible moves!\nYour knight visited {self.movements_made + 1} squares!")
return False
# Resets the Knight position to the initial for the ai_play function
def knight_reset(self):
main_move = self.knight_move(self.initial_move_for_ai, solution_mode=True)
return main_move
# Helper function that manages the outputs of the ai_play function regarding if player want a solution or not
def ai_solution_test(self, move, for_player=False):
if self.board_dimensions in {16, 4, 9}:
print("No solution exists!")
return False
self.initial_move_for_ai = move
self.find_solution_mode = True
movement = self.knight_move(move, solution_mode=True)
self.set_first()
self.initial_move_for_ai = movement
valid_moves = self.get_valid_moves(movement)
while True:
self.ai_play(movement, valid_moves, 1)
if self.has_solution:
if not for_player:
print("\nHere's the solution!")
print(self.__str__())
break
else:
break
self.find_solution_mode = False
self.ai_play_reset()
return True
def __str__(self):
visualization = [" ".rjust(self.cell_length - 1) + "-" * (self.x * (self.cell_length + 1) + 3)]
for i in range(len(self.visual)):
main_chess = " ".join([str(len(self.visual) - i).rjust(self.cell_length - 1) + "|", *self.visual[i], "|"])
visualization.append(main_chess)
visualization.append(" " * (self.cell_length - 1) + "-" * (self.x * (self.cell_length + 1) + 3))
visualization.append(
" ".rjust(self.cell_length + 2) + " ".join([f"{i}".center(self.cell_length) for i in range(1, self.x + 1)]))
return "\n".join(visualization)
def main():
while True:
board = ChessBoard(input("Enter your board's dimensions: "))
if not board.valid_grid:
print("Invalid dimensions!", end=" ")
continue
while True:
knight_move = board.move_validation(input("Enter the knight's starting position: "))
if not knight_move:
print("Invalid move!", end=" ")
continue
else:
break
while True:
puzzle_try = input("Do you want to try the puzzle? (y/n): ")
if puzzle_try not in {"y", "n"}:
print("Invalid input!", end=" ")
continue
else:
break
if puzzle_try == "y":
check_if_solution = board.ai_solution_test(knight_move, for_player=True)
if check_if_solution:
board.knight_move(knight_move)
while not board.game_over:
next_move = board.knight_move(input("Enter your next move: "))
if next_move:
board.board_updater()
else:
print("Invalid move!", end=" ")
continue
if board.game_over:
break
else:
break
else:
board.ai_solution_test(knight_move)
break
if __name__ == "__main__":
main()

How to search for the index of the number from the last of list to first?

I was checking the documentation to find the index of the number from last to first.
I could use - list.index(number, start, end). In my example, if I omit the start and end I don't get any exception. However, I get an exception when I change the start to the last index and end to the first element index i.e. 0. I am sure I am doing something wrong but I am unable to think about what is going wrong here.
def nonConstructibleChange(coins):
# o(log n) - sorting
coins.sort() # O(log n)
max_amount = sum(coins)
print(max_amount)
# range is [start, end)
if len(coins) == 0:
return 1
for change in range(1, max_amount+1):
if change == 1:
if 1 not in coins:
return 1
else:
max_limit = change - 1
while max_limit not in coins and max_limit != -1:
max_limit -=1
print(coins.index(max_limit, len(coins)-1, 0)) # throws exception
print(coins.index(max_limit)) # this works
if __name__ == '__main__':
coins = [5, 7, 1, 1, 2, 3, 22]
nonConstructibleChange(coins)
You can find the index of the last occurrence of an element by applying index function on the reversed list. In your case this would be:
print(coins[::-1].index(max_limit))
def nonConstructibleChange(coins):
# o(log n) - sorting
coins.sort() # O(log n)
max_amount = sum(coins)
num = None
#print(coins)
#print(max_amount)
# range is [start, end)
if len(coins) == 0:
return 1
for change in range(1, max_amount+1):
if change == 1:
if 1 not in coins:
return 1
else:
max_limit = change
while max_limit not in coins and max_limit != -1:
max_limit -=1
right_index = coins.index(max_limit)
while 1:
try:
# the last index is not included therefore len(coins)
right_index = coins.index(max_limit, right_index +1 , len(coins))
except ValueError:
# print(f'final right_index = {right_index}')
break
print(f'right_index = {right_index}')
print(f'change = {change}')
print(f'max_limit = {max_limit}')
num = change
for idx in reversed(range(right_index + 1)):
if coins[idx] > num:
#print(f'coins[idx] = {coins[idx]} and num = {num}')
continue
#print(f'idx = {idx}')
num = num - coins[idx]
#print(f'num = {num}')
if (num in coins[0:idx-1] or num == 0) and idx != 0:
#print(f'Setting num = {num}')
num = 0
break
if num != 0:
return change
return max_amount + 1
if __name__ == '__main__':
coins = [5, 7, 1, 1, 2, 3, 22]
#coins = [1, 1, 1, 1, 1]
print(nonConstructibleChange(coins))

Why aren't the values from my arrays passing though my full bit adder

# 8-bit-binary adder
#if you have questions about the code just ask
# arrays and funtions
Array1 = []
Array2 = []
#Input A and Validation
def vaildNumberA():
a = int(input("Enter your A value:"))
if (a < 0):
print("Please Enter A Valid Number For Input A")
elif (a > 255):
print("Please Enter A Valid Number For Input A")
else:
Array1 = [int(x) for x in list('{0:08b}'.format(a))]
#Input B and Validation
def vaildNumberB():
b = int(input("Enter your B value:"))
if (b < 0):
print("Please Enter A Valid Number For Input B")
elif (b > 255):
print("Please Enter A Valid Number For Input B")
else:
Array2 = [int(x) for x in list('{0:08b}'.format(b))]
# and gate
# AND Gate
def AND (a,b):
if (a == 1 and b == 1):
return 1
else:
return 0
# or gate
#OR Gate
def OR(a,b):
if (a == 1 or b == 1):
return 1
else:
return 0
# XOR GATEE
#XOR Gate
def XOR (a,b):
if (a == b):
return 0
else:
return 1
#carry formula
def carryformula(a,b,c,d):
return OR(AND(a,b), AND(c,d))
# this is where the calculation should be done
#formula for sum
def calculateSum(Array1,Array2):
carry = ""
sumof = []
for index, in range(len(Array1)):
list2 = Array2[index]
sec_xor_form = XOR(Array1[index],Array2[index])
sumof.append(XOR(sec_xor_form,carry))
carry = carryformula(Array1[index],Array2[index],sec_xor_form,carry)
return list(reversed(sumof))
calculateSum(Array1,Array2)
def main(Array1,Array2):
vaildNumberA()
vaildNumberB()
while True:
a = Array1
b = Array2
total = calculateSum(list(reversed(Array1)),list(reversed(Array2)))
print(total)
quit = input("if want to quit type q: ")
if quit == 'q':
break
main(Array1,Array2)
in the send it prints 0
The only problem in your code is that you need to return Array1 and Array2 from your functions and assign them inside the while true loop, once you do that the code works fine.
The updated code will be
# 8-bit-binary adder
#if you have questions about the code just ask
# arrays and funtions
Array1 = []
Array2 = []
#Input A and Validation
def vaildNumberA():
Array1 = []
a = int(input("Enter your A value:"))
if (a < 0):
print("Please Enter A Valid Number For Input A")
elif (a > 255):
print("Please Enter A Valid Number For Input A")
else:
Array1 = [int(x) for x in list('{0:08b}'.format(a))]
#Return the array
return Array1
#Input B and Validation
def vaildNumberB():
Array2 = []
b = int(input("Enter your B value:"))
if (b < 0):
print("Please Enter A Valid Number For Input B")
elif (b > 255):
print("Please Enter A Valid Number For Input B")
else:
Array2 = [int(x) for x in list('{0:08b}'.format(b))]
#Return the array
return Array2
# AND Gate
def AND (a,b):
if (a == 1 and b == 1):
return 1
else:
return 0
#OR Gate
def OR(a,b):
if (a == 1 or b == 1):
return 1
else:
return 0
#XOR Gate
def XOR (a,b):
if (a == b):
return 0
else:
return 1
#carry formula
def carryformula(a,b,c,d):
return OR(AND(a,b), AND(c,d))
# this is where the calculation should be done
#formula for sum
def calculateSum(Array1,Array2):
carry = ""
sumof = []
for index in range(len(Array1)):
list2 = Array2[index]
sec_xor_form = XOR(Array1[index],Array2[index])
sumof.append(XOR(sec_xor_form,carry))
carry = carryformula(Array1[index],Array2[index],sec_xor_form,carry)
return list(reversed(sumof))
#No need of a main function
while True:
#Call the function from within the while True loop
Array1 = vaildNumberA()
Array2 = vaildNumberB()
total = calculateSum(list(reversed(Array1)),list(reversed(Array2)))
print(total)
quit = input("if want to quit type q: ")
if quit == 'q':
break
And the output will look like
Enter your A value:5
Enter your B value:5
[0, 0, 0, 0, 1, 0, 1, 1]
if want to quit type q: 7
Enter your A value:9
Enter your B value:8
[0, 0, 0, 1, 0, 0, 0, 1]
....

I want to return control to it starting point using function in a class in Python 3

I have 3 different functions in a class if the command in any of the function returns false, I want the program to begin all over again the way it started if the function that returns false was the last command among the function. Also, I want the program to return to the last successful function command if the failed command is not the last among the functions
When I run the program and last function command fails, the program returned to the starting point but ignore certain and crucial part of what I want to achieve, rather it full execute the second function command
class Test():
def greeting(self):
user_input = input("Greeting: ")
print("This is the greeting function")
list1 = ["hello", "Hi"]
if user_input in list1:
print("Thats good")
Test.cities(self)
elif user_input not in list1:
print("Mtchewwww")
Test.greeting(self)
else:
print("be serious")
def cities(self):
print("U re now inside the city function")
list2 = ["Otukpo", "Gboko"]
user_input = input("Cities: ")
if user_input in list2:
print("Nice one")
Test.num(self)
else:
print("that's not a city")
Test.cities(self)
def num(self):
user_input = input("Numbers: ")
list3 = [1, 2, 3, 4]
if int(user_input) in list3:
print("good number")
elif user_input not in list3:
print("That was bad")
Test.greeting(self)
else:
print("Can not compute")
calling = Test()
cal = calling.greeting
cal()
I want the program to behave like this:
if item is in list1 move to the next function but if not in list, try the current function again 3 times and after the the 3 chances and it's still not in the list return to the previous function
def greeting():
user_input = input("Greeting: ")
# It is not good to name your variables like `list1`, `str2`...
# plus, if your list is immutable, use a tuple instead.
options = ('hello', 'Hi')
if user_input in options:
print("That's good")
return True
else:
return False
def cities():
user_input = input("Cities: ")
options = ("Otukpo", "Gboko")
if user_input in options:
print("Nice one")
return True
else:
print("That's not a city")
return False
def num():
user_input = input("Numbers: ")
options = (1, 2, 3, 4)
try:
if int(user_input) in options:
print("Good number")
return True
else:
return False
except ValueError:
# In case that the input is not a number
return False
def main():
fns = (greeting, cities, num)
ptr = 0
cnt = 0
# Just for your information, you don't have to use `ptr >= 0 and ptr <3` in python
while 0 <= ptr < 3:
# print(ptr, cnt)
if cnt >= 3:
# if failed for 3 times, move `ptr` to the previous function, and reset `cnt` to 0
ptr -= 1
cnt = 0
continue
# Get the current function, as `fn`
fn = fns[ptr]
if fn():
# if the current function is a success, move to next, and reset `cnt`
ptr += 1
cnt = 0
else:
# if the current function is a failure, it will be tried again in next while loop
cnt += 1
main()
Use a pointer ptr to iterate over your three functions, and use a variable cnt to limit the failure times. Just try it.
Have fun with python!

Object() takes no arguments

I get, "TypeError: Question() takes no arguments" (where Question is an object of class Question) when trying to execute the code below.
I'm using jupyter notebook and have checked most of my indentation, Tthe class Question has 2 attributes, I have an init method...
Issue is related to the function find_best_split(rows) below.
I have added an image of the error console output here
class Question:
def __init__(self, column, value):
self.column = column
self.value = value
def match(self, example):
val = example[self.column]
if is_numeric(val):
return val >= self.value
else:
return val == self.value
def __repr__(self):
condition = "=="
if is_numeric(self.value):
condition = ">="
return "Is %s %s %s?" % (header[self.column], condition, str(self.value))
def partition(rows, question):
true_rows, false_rows = [], []
for row in rows:
if question.match(row):
true_rows.append(row)
else:
false_rows.append(row)
return true_rows, false_rows
` Error points to this function, specifically "question = Question(col, val)"
def find_best_split(rows):
best_gain = 0
best_question = None
current_uncertainty = gini(rows)
n_features = len(rows[0]) -1 # number of columns
for col in range(n_features):
values = set([row[col] for row in rows]) # unique values in the column
for val in values: #now for each value
question = Question(col, val)
# trying to split the data set
true_rows, false_rows = partition(rows, question)
# skips this split if it doesn't divide the data set.
if len(true_rows) == 0 or len(false_rows) == 0:
continue
# calculate the information gain from this split
gain = info_gain(true_rows, false_rows, current_uncertainty)
# you can use > instead of >= below but I wanted the data set to look a certain way for this example.
if gain >= best_gain:
best_gain, best_question = gain, question
return best_gain, best_quesiton
`
class Decision_Node:
def __init__(self, question, true_branch, false_branch):
self.question = question
self.true_branch = true_branch
self.false_branch = false_branch
def build_tree(rows):
gain, question = find_best_split(rows)
if gain == 0:
return Leaf(rows)
true_rows, false_rows = partition(rows, question)
true_branch = build_tree(true_rows)
false_branch = build_tree(false_rows)
return Decision_Node(question, true_branch, false_branch)
if __name__ == '__main__':
my_tree = build_tree(training_data)
print_tree(my_tree)
# Evaluate
testing_data = [
["Green", 3, "Mango"],
["Yellow", 4, "Mango"],
["Red", 2, "Grape"],
["Red", 1, "Grape"],
["Yellow", 3, "Lemon"],
]
for row in testing_data:
print ("Actual: %s. Predicted: %s" % (row[-1], print_leaf(classify(row, my_tree))))

Resources