Simple loop bug which i forgot [closed] - python

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 1 year ago.
Improve this question
I want to build a list. The list have the number of values asked for from the user, and can't pass the limit and can't repeat, but I don't know where my error is. The program doesn't build the list by the way I want to. It's a bit hard to explain, but run the code by yourself with the attributes:
class Mundo:
def __init__(self):
self.existValues = list()
self.world = self.grid()
self.blues = self.blue()
print(f"Map: {self.world}\n"
f"Exist Values: {self.existValues}\n"
f"Blue values: {self.blues}")
# self.theArray = [[self.world, ], [self.world, ]]
def grid(self):
while True:
self.size = input("Size of Map: ")
if self.size.isnumeric() and int(self.size) >= 2:
self.size = int(self.size)
intSize = self.size * self.size
mapH = list()
gridMap = list()
for elementos in range(1, intSize + 1):
if len(mapH) == self.size - 1:
mapH.append(elementos)
gridMap.append(mapH)
mapH = []
else:
mapH.append(elementos)
return gridMap
def blue(self):
while True:
try:
qt = int(input("How many blues to spawn?"))
except ValueError:
continue
posBlue = list()
controle = list()
control = False
for _ in range(qt):
while not control:
x = rint(1, self.size)
y = rint(1, self.size)
controle.append([x, y])
for elements in controle:
if elements in self.existValues:
control = True
else:
posBlue.append([x, y])
self.existValues.append([x, y])
control = False
return posBlue
If i run the code (being that qt == 2, and self.size == 4 ), one, two or three times the code outputs a list that contains 3 or 2 values, and sometimes 4.
I will run 3 times to show.
Output 1:
Only 3 values in blues, i asked for 4.
Output 2:
Only 2, i ask for 4.
Output 3:
Again.
I need that output that the user ask.

Here's your code in more of an MRE form:
from random import randint
def blue(qt: int, size: int):
existValues = []
posBlue = list()
controle = list()
for _ in range(qt):
x = randint(1, 4)
y = randint(1, 4)
controle.append([x, y])
for elements in controle:
if elements in existValues:
continue
else:
posBlue.append([x, y])
existValues.append([x, y])
return posBlue
print(len(blue(2, 4))) # prints 2 because odds are good of getting 2 uniques
print(len(blue(10, 4))) # prints 8 because it missed some
print(len(blue(100, 4))) # prints 16 because that's the maximum number
By testing with different quantities, it's easy to see where the problem is -- you're dependent on random chance to generate unique combinations, so there's not a guarantee that each iteration of your for loop is going to find a combination that doesn't already exist.
The easy way to do this is to generate an exhaustive list of combinations and then select them randomly:
from itertools import product
from random import sample
def blue(qt: int, size: int):
possibilities = list(product(range(1, size+1), range(1, size+1)))
return sample(possibilities, qt)
print(len(blue(2, 4))) # prints 2
print(len(blue(10, 4))) # prints 10
print(len(blue(100, 4))) # ValueError: Sample larger than population
Note that this raises an exception if qt is greater than size^2. You can decide if you want to handle this a different way -- maybe given a sufficiently large quantity repeats are acceptable? Here's a simple approach to making that fix: multiply possibilities by the quantity necessary to ensure that it's at least as big as qt.
def blue(qt: int, size: int):
possibilities = list(product(range(1, size+1), range(1, size+1)))
possibilities *= 1 + (qt - 1) // len(possibilities)
return sample(possibilities, qt)

Related

Find minimum number of elements in a list that covers specific values

A recruiter wants to form a team with different skills and he wants to pick the minimum number of persons which can cover all the required skills.
N represents number of persons and K is the number of distinct skills that need to be included. list spec_skill = [[1,3],[0,1,2],[0,2,4]] provides information about skills of each person. e.g. person 0 has skills 1 and 3, person 1 has skills 0, 1 and 2 and so on.
The code should outputs the size of the smallest team that recruiter could find (the minimum number of persons) and values indicating the specific IDs of the people to recruit onto the team.
I implemented the code with brute force as below but since some data are more than thousands, it seems I need to be solved with heuristic approaches. In this case it is possible to have approximate answer.
Any suggestion how to solve it with heuristic methods will be appreciated.
N,K = 3,5
spec_skill = [[1,3],[0,1,2],[0,2,4]]
A = list(range(K))
set_a = set(A)
solved = False
for L in range(0, len(spec_skill)+1):
for subset in itertools.combinations(spec_skill, L):
s = set(item for sublist in subset for item in sublist)
if set_a.issubset(s):
print(str(len(subset)) + '\n' + ' '.join([str(spec_skill.index(item)) for item in subset]))
solved = True
break
if solved: break
Here is my way of doing this. There might be potential optimization possibilities in the code, but the base idea should be understandable.
import random
import time
def man_power(lst, K, iterations=None, period=0):
"""
Specify a fixed number of iterations
or a period in seconds to limit the total computation time.
"""
# mapping each sublist into a (sublist, original_index) tuple
lst2 = [(lst[i], i) for i in range(len(lst))]
mini_sample = [0]*(len(lst)+1)
if period<0 or (period == 0 and iterations is None):
raise AttributeError("You must specify iterations or a positive period")
def shuffle_and_pick(lst, iterations):
mini = [0]*len(lst)
for _ in range(iterations):
random.shuffle(lst2)
skillset = set()
chosen_ones = []
idx = 0
fullset = True
# Breaks from the loop when all skillsets are found
while len(skillset) < K:
# No need to go further, we didn't find a better combination
if len(chosen_ones) >= len(mini):
fullset = False
break
before = len(skillset)
skillset.update(lst2[idx][0])
after = len(skillset)
if after > before:
# We append with the orginal index of the sublist
chosen_ones.append(lst2[idx][1])
idx += 1
if fullset:
mini = chosen_ones.copy()
return mini
# Estimates how many iterations we can do in the specified period
if iterations is None:
t0 = time.perf_counter()
mini_sample = shuffle_and_pick(lst, 1)
iterations = int(period / (time.perf_counter() - t0)) - 1
mini_result = shuffle_and_pick(lst, iterations)
if len(mini_sample)<len(mini_result):
return mini_sample, len(mini_sample)
else:
return mini_result, len(mini_result)

How can we develop an algorithm to solve a problem of DP [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 1 year ago.
Improve this question
could someone plz solve this question using python language?
You can use DP to solve it. Here is a good website for learning DP: https://www.geeksforgeeks.org/dynamic-programming/
# For example X=3, Y=5, D=24. If we know solution for D=21 (24-3) and D=19 (24-5), then we know for D=24 the solution is min(D=21, D=19) +1.
# And for D=19, we know it's min(D=16, D=14) +1. So all the way back to D=3 and D=5.
def sol(X,Y,D):
# dp list for storing the solution for each D.
# For inner list, index 0 represent the usage of X, index 1 represent the usage of Y.
dp = [[float('inf'), float('inf')] for _ in range(D+1)]
# Assume X <= D and Y <= D, it guarantees both X and Y can fit in D.
# for D=X, the solution is 1X, 0Y, so it's[1,0]
dp[X] = [1,0]
# for D=Y, the solution is 0X, 1Y, so it's[0,1]
dp[Y] = [0,1]
for i in range(min(X,Y)+1, D+1):
# If already has a solution, skip.
if dp[i][0] != float('inf'):
continue
# Current D= min(D-X, D-Y) + 1
if sum(dp[i-X]) < sum(dp[i-Y]):
dp[i][0] = dp[i-X][0]+1
dp[i][1] = dp[i-X][1]
else:
dp[i][0] = dp[i-Y][0]
dp[i][1] = dp[i-Y][1]+1
# Search for a solution backward.
for i in range(len(dp)-1, -1, -1):
if dp[i][0] != float('inf') and dp[i][1] != float('inf'):
return (D-i, dp[i][0], dp[i][1])
return (D-i, 0, 0)
print(sol(3,5,24))
Here is a simplified question for understanding DP:
'''
To make it easier understand, let's simplify the question: we just want to know the minimium number of tables to get to D.
For example, X=3, Y=5, D=15.
'''
def sol(X,Y,D):
# 1. We create a list of size D+1: dp = [None, None, None, ....], +1 just for easier calculation. Since the index starts at 0.
# float('inf') represents infinity number, just for easier to use below. You will see it later.
dp = [float('inf') for _ in range(D+1)]
# 2. Our base case: when D=3, we know X=1,Y=0 is the solution, so only need 1 table to get to D=3.
# Same for D=5: when D=5, we know X=0,Y=1 is the solution.
# So set our base case: dp[3] = 1, dp[5] = 1
dp[X] = 1
dp[Y] = 1
# 4. Now the list is dp = [None, None, None, 1, None, 1, None, ....]
# 5. For D < min(X, Y), that's for sure no solution.
# So we start calculating solution for each D > min(X,Y) (D=min(X,Y) is our base case)
for i in range(min(X,Y)+1, D+1):
# If already has a solution, skip. This is for preventing overwrite case such as Y can be formed by X.
# For example, X=3, Y=6, on dp[6] we don't want the solution from dp[6-3].
if dp[i] != float('inf'):
continue
# 7. Let's take example at D=8. The solution could D=3 + 1 table, or D=5 + 1 table.
# Since we want the minimum, so our solution for D=8 is: min(D-3, D-5) + 1
# Here is the reason we initiate value is float('inf') instead of None.
# We don't have to check if it's None before calculate.
# For example D=7, D-3 is None, D-5 is None. min(None, None) throws error,
# we have to check if it's None or not before calculate. But if we use float('inf'),
# min(float('inf'), float('inf')) + 1 is still float('inf').
dp[i] = min(dp[i-X], dp[i-Y]) + 1
# 8. Search for a smallest distance solution. For D=24, there is already a solution, so return dp[24]
# But some D don't have solution. For example D=7 doesn't have a solution, so we check, D=6, D=5.. until
# it finds a solution. And that's the smallest distance solution.
for i in range(len(dp)-1, -1, -1):
if dp[i] != float('inf'):
# first element is the distance, second is the number of tables.
return (D-i, dp[i])
return (D-i, 0)
print(sol(3,5,15))
i think this is what you are looking for
NOTE: THE VALUE OF X IS GREATER THAN Y.
def table_arrange(x,y,d):
list_of_lists = []
a = d//x
b = list(x for i in range(0,a))
while sum_of_list(b)+y <= d:
b.append(y)
array = b.copy()
list_of_lists.append(array)
list_of_lists = arrange(list_of_lists,b,x,y,d)
differnce = y
optimum = []
for lists in list_of_lists:
a = d - sum_of_list(lists)
if differnce > a:
optimum = lists
differnce = a
f = optimum.count(x)
g = optimum.count(y)
return [f,g,differnce]
def arrange(list_of_lists,b,x,y,d):
c = []
for i in range(b.count(x)):
b.pop(0)
while sum_of_list(b)+y <= d:
b.append(y)
c = b.copy()
list_of_lists.append(c)
return list_of_lists
def sum_of_list(list_):
a = 0
for i in list_:
a = a+i
return a
print(table_arrange(5,3,21))

Genetic Algorithm for 8 queens puzzle

I'm trying to apply genetic algorithm for 8 queens puzzle. I've coded whole algorithm but it keeps getting stuck when it finds solution with 6 unhit queens and can't get over it. I feel like there's some diversity problem but I can't figure out what to do with it. My question is what is wrong with this realisation and why it keeps getting stuck on 6 unhit queens and can't make a final move? I've already examined every bit of code and I think there's some misinterpretation of algorithm itself evolved. That's why I attached whole code. So I hope that someone would tell me where I did wrong. Thanks in advance.
def mutate(self, children):
rnd.seed()
count = 0
for child in children:
count += 1
if rnd.random() < self.mut_prob:
i = rnd.randrange(0, 7)
ind = child[i].index(1)
child[i][ind] = 0
j = rnd.randrange(0, 7)
child[i][j] = 1
def solve(self, min_fitness= 7, max_epochs=100):
prev_pop = self.initial_population()
epochs = 0
max_fitness = 0
while (max_fitness <= min_fitness) and (epochs < max_epochs):
fitness = self.fitness_function(prev_pop)
fitness.sort(key=lambda tup: tup[1])
best_sol = fitness[len(fitness) - 1][0]
max_fitness = fitness[len(fitness) - 1][1]
mating = self.roulette(fitness)
mating_chromes = []
pop = copy.deepcopy(prev_pop)
for chrom in mating:
mating_chromes.append(pop[chrom])
pop.clear()
children = self.crossover(mating_chromes)
self.mutate(children)
fit = self.fitness_function(prev_pop)
to_destroy = self.reduction(fitness)
for el in to_destroy:
prev_pop[el] = children.pop(0)
epochs += 1
print(max_fitness)
print(epochs)
for el in prev_pop[best_sol]:
print(el)
print("\n")
print("im fine")
return 0
s = Solver_8_queens()
arr = s.solve()
One problem with your code is the way you use Python function random.randrange(). The documentation says that randrange(a, b) will return a random number x such that a <= x < b (note that b is not included).
When you write something like i = random.randrange(0, 7) you will get a random number from the semi-open interval [0, 7), while what you (most likely) want is the number from closed interval [0, 7], because board size is 8x8. So check all calls to randrange(), fix them if they are incorrect and see whether it solves the problem.

backtracking not trying all possibilities

so I've got a list of questions as a dictionary, e.g
{"Question1": 3, "Question2": 5 ... }
That means the "Question1" has 3 points, the second one has 5, etc.
I'm trying to create all subset of question that have between a certain number of questions and points.
I've tried something like
questions = {"Q1":1, "Q2":2, "Q3": 1, "Q4" : 3, "Q5" : 1, "Q6" : 2}
u = 3 #
v = 5 # between u and v questions
x = 5 #
y = 10 #between x and y points
solution = []
n = 0
def main(n_):
global n
n = n_
global solution
solution = []
finalSolution = []
for x in questions.keys():
solution.append("_")
finalSolution.extend(Backtracking(0))
return finalSolution
def Backtracking(k):
finalSolution = []
for c in questions.keys():
solution[k] = c
print ("candidate: ", solution)
if not reject(k):
print ("not rejected: ", solution)
if accept(k):
finalSolution.append(list(solution))
else:
finalSolution.extend(Backtracking(k+1))
return finalSolution
def reject(k):
if solution[k] in solution: #if the question already exists
return True
if k > v: #too many questions
return True
points = 0
for x in solution:
if x in questions.keys():
points = points + questions[x]
if points > y: #too many points
return True
return False
def accept(k):
points = 0
for x in solution:
if x in questions.keys():
points = points + questions[x]
if points in range (x, y+1) and k in range (u, v+1):
return True
return False
print(main(len(questions.keys())))
but it's not trying all possibilities, only putting all the questions on the first index..
I have no idea what I'm doing wrong.
There are three problems with your code.
The first issue is that the first check in your reject function is always True. You can fix that in a variety of ways (you commented that you're now using solution.count(solution[k]) != 1).
The second issue is that your accept function uses the variable name x for what it intends to be two different things (a question from solution in the for loop and the global x that is the minimum number of points). That doesn't work, and you'll get a TypeError when trying to pass it to range. A simple fix is to rename the loop variable (I suggest q since it's a key into questions). Checking if a value is in a range is also a bit awkward. It's usually much nicer to use chained comparisons: if x <= points <= y and u <= k <= v
The third issue is that you're not backtracking at all. The backtracking step needs to reset the global solution list to the same state it had before Backtracking was called. You can do this at the end of the function, just before you return, using solution[k] = "_" (you commented that you've added this line, but I think you put it in the wrong place).
Anyway, here's a fixed version of your functions:
def Backtracking(k):
finalSolution = []
for c in questions.keys():
solution[k] = c
print ("candidate: ", solution)
if not reject(k):
print ("not rejected: ", solution)
if accept(k):
finalSolution.append(list(solution))
else:
finalSolution.extend(Backtracking(k+1))
solution[k] = "_" # backtracking step here!
return finalSolution
def reject(k):
if solution.count(solution[k]) != 1: # fix this condition
return True
if k > v:
return True
points = 0
for q in solution:
if q in questions:
points = points + questions[q]
if points > y: #too many points
return True
return False
def accept(k):
points = 0
for q in solution: # change this loop variable (also done above, for symmetry)
if q in questions:
points = points + questions[q]
if x <= points <= y and u <= k <= v: # chained comparisons are much nicer than range
return True
return False
There are still things that could probably be improved in there. I think having solution be a fixed-size global list with dummy values is especially unpythonic (a dynamically growing list that you pass as an argument would be much more natural). I'd also suggest using sum to add up the points rather than using an explicit loop of your own.

How to format a floating number to maximum fixed width in Python

I am writing an input file to a program with roots in the 60s, and it reads data from fixed-width data fields on text files. The format is:
field width 8 characters
floating point numbers must contain a '.' or be written on exponential format, e.g. '1.23e8'
The closest i've gotten is
print "{0:8.3g}".format(number)
which yields '1.23e+06' with 1234567, and ' 1234' with 1234.
I would like to tweak this however, to get
'1234567.' with 1234567 (i.e. not going to exponential format before it is
required),
' 1234.' with 1234 (i.e. ending with a dot so it is not interpreted as an integer),
'1.235e+7' with 12345678 (i.e. using only one digit for the exponent),
'-1.23e+7' with -1234567 (i.e. not violating the 8 digit maximum on
negative numbers).
Since this is (as far as I recall) easily achievable with Fortran and the problem probably comes up now and then when interacting with legacy code I suspect that there must be some easy way to do this?
I simply took the answer by #Harvey251 but split into test part and the part we need in production.
Usage would be:
# save the code at the end as formatfloat.py and then
import formatfloat
# do this first
width = 8
ff8 = formatfloat.FormatFloat(width)
# now use ff8 whenever you need
print(ff8(12345678901234))
And here is the solution. Save the code as formatfloat.py and import it to use FlotFormat class. As I said below, loop part of calculation better be moved to init part of the FormatFlot class.
import unittest
class FormatFloat:
def __init__(self, width = 8):
self.width = width
self.maxnum = int('9'*(width - 1)) # 9999999
self.minnum = -int('9'*(width - 2)) # -999999
def __call__(self, x):
# for small numbers
# if -999,999 < given < 9,999,999:
if x > self.minnum and x < self.maxnum:
# o = f'{x:7}'
o = f'{x:{self.width - 1}}'
# converting int to float without adding zero
if '.' not in o:
o += '.'
# float longer than 8 will need rounding to fit width
elif len(o) > self.width:
# output = str(round(x, 7 - str(x).index(".")))
o = str(round(x, self.width-1 - str(x).index('.')))
else:
# for exponents
# added a loop for super large numbers or negative as "-" is another char
# Added max(max_char, 5) to account for max length of less
# than 5, was having too much fun
# TODO can i come up with a threshold value for these up front,
# so that i dont have to do this calc for every value??
for n in range(max(self.width, 5) - 5, 0, -1):
fill = f'.{n}e'
o = f'{x:{fill}}'.replace('+0', '+')
# if all good stop looping
if len(o) == self.width:
break
else:
raise ValueError(f"Number is too large to fit in {self.width} characters", x)
return o
class TestFormatFloat(unittest.TestCase):
def test_all(self):
test = (
("1234567.", 1234567),
("-123456.", -123456),
("1.23e+13", 12345678901234),
("123.4567", 123.4567),
("123.4568", 123.45678),
("1.234568", 1.2345678),
("0.123457", 0.12345678),
(" 1234.", 1234),
("1.235e+7", 12345678),
("-1.23e+6", -1234567),
)
width = 8
ff8 = FormatFloat(width)
for expected, given in test:
output = ff8(given)
self.assertEqual(len(output), width, msg=output)
self.assertEqual(output, expected, msg=given)
if __name__ == '__main__':
unittest.main()
I've made a slight addition to yosukesabai's contribution to account for the rare case where rounding will make the width of the string 7 characters instead of 8!
class FormatFloat:
def __init__(self, width = 8):
self.width = width
self.maxnum = int('9'*(width - 1)) # 9999999
self.minnum = -int('9'*(width - 2)) # -999999
def __call__(self, x):
# for small numbers
# if -999,999 < given < 9,999,999:
if x > self.minnum and x < self.maxnum:
# o = f'{x:7}'
o = f'{x:{self.width - 1}}'
# converting int to float without adding zero
if '.' not in o:
o += '.'
# float longer than 8 will need rounding to fit width
elif len(o) > self.width:
# output = str(round(x, 7 - str(x).index(".")))
o = str(round(x, self.width - 1 - str(x).index('.')))
if len(o) < self.width:
o+=(self.width-len(o))*'0'
else:
# for exponents
# added a loop for super large numbers or negative as "-" is another char
# Added max(max_char, 5) to account for max length of less
# than 5, was having too much fun
# TODO can i come up with a threshold value for these up front,
# so that i dont have to do this calc for every value??
for n in range(max(self.width, 5) - 5, 0, -1):
fill = f'.{n}e'
o = f'{x:{fill}}'.replace('+0', '+')
# if all good stop looping
if len(o) == self.width:
break
else:
raise ValueError(f"Number is too large to fit in {self.width} characters", x)
return o
You've clearly gotten very close, but I think your final solution is going to involve writing a custom formatter. For example, I don't believe the mini-formatting language can control the width of the exponent like you want.
(BTW, in your first example you don't have a "+" after the "e" but in the others you do. Making it clear which one you want might help other answerers.)
If I were writing this formatting function, the first thing I would do is write a thorough set of tests for it. Either doctest or unittest would be suitable.
Then you work on your formatting function until all those tests pass.
You could do something like, admittedly it's a little late and I spent way too long on it, but I came upon this when trying to figure out something similar.
import unittest
class TestStringMethods(unittest.TestCase):
def test_all(self):
test = (
("1234567.", 1234567),
("-123456.", -123456),
("1.23e+13", 12345678901234),
("123.4567", 123.4567),
("123.4568", 123.45678),
("1.234568", 1.2345678),
("0.123457", 0.12345678),
(" 1234.", 1234),
("1.235e+7", 12345678),
("-1.23e+6", -1234567),
)
max_char = 8
max_number = int("9" * (max_char - 1)) # 9,999,999
min_number = -int("9" * (max_char - 2)) # -999,999
for expected, given in test:
# for small numbers
# if -999,999 < given < 9,999,999:
if min_number < given < max_number:
# output = f"{given:7}"
output = f"{given:{max_char - 1}}"
# converting ints to floats without adding zero
if '.' not in output:
output += '.'
# floats longer than 8 will need rounding to fit max length
elif len(output) > max_char:
# output = str(round(given, 7 - str(given).index(".")))
output = str(round(given, max_char - 1 - str(given).index(".")))
else:
# for exponents
# added a loop for super large numbers or negative as "-" is another char
# Added max(max_char, 5) to account for max length of less than 5, was having too much fun
for n in range(max(max_char, 5) - 5, 0, -1):
fill = f".{n}e"
output = f"{given:{fill}}".replace('+0', '+')
# if all good stop looping
if len(output) == max_char:
break
else:
raise ValueError(f"Number is too large to fit in {max_char} characters", given)
self.assertEqual(len(output), max_char, msg=output)
self.assertEqual(output, expected, msg=given)
if __name__ == '__main__':
unittest.main()

Categories

Resources