how can I increment the first number in a range? - python-3.x

Learning python and I need to figure out to to increase the first number in a range?
measures = 4
beats_per_measures = 4
beats = 0
for i in range(0, measures):
for beats in range(1 , beats_per_measure + 1):
print(beats)
so I can get the output to print the beats per measure the number of measures. BOOm. but now I need to increase the first beat by one every measure and I know it's easier than I am making it. I have preformed multiple searches online and I am guessing that because I don't know how to read the complex answers or I don't know how to phrase what I am trying to do is why I have not found an answer yet.

Is this what you need?
I thought you needed each set (1,2,3,4) in the same line.
measures = 4
beats_per_measure = 4
for i in range(measures):
for var_beat in range(beats_per_measure):
var_beat = str(1 + var_beat)
fixed_beat = ' '.join([ str(1+f) for f in range(beats_per_measure)[1:]])
print(var_beat + ' ' + fixed_beat)
I am a little bit confused with your "so on" in your comment.

You can do:
for e in range(1,5):
print(', '.join(map(str, ([e]+list(range(2,5))))))
Prints:
1, 2, 3, 4
2, 2, 3, 4
3, 2, 3, 4
4, 2, 3, 4
Or, perhaps:
>>> print('\n'.join([f"{e}, 2, 3 ,4" for e in range(1,5)]))
# same output
Which could be made dynamic by this:
measures = 4
beats_per_measures = 4
rest_of_measure=', '.join(f'{e}' for e in range(2,beats_per_measures+1))
print('\n'.join([f"{e}, {rest_of_measure}" for e in range(1, measures+1)]))

From your comment, you just want to always print an increasing number followed by 2, 3, 4. So just print the first beat manually based on the measure you're currently processing:
for measure in range(1, measures+1): # Adjust bounds so we don't have to add one inside the loop
print(measure) # Prints the changing value
for beats in range(2, beats_per_measure + 1):
print(beats) # Prints the consistent 2, 3, 4 values
If you want each measure on the same line, the minimal change is to just add end='' or end=' ' to each print and add an empty print() to the end of the outer loop.
A cleaner solution would be to just print each measure all at once; you can unpack a range argument with * to make it operate as separate arguments to print, and use sep to provide the characters you want in between, getting something like:
for measure in range(1, measures + 1):
print(measure, *range(2, beats_per_measure + 1), sep=', ')
# prints:
1, 2, 3, 4
2, 2, 3, 4
3, 2, 3, 4
...
and it's trivial to change the separation to just a single space, sep=' ', or no separation at all, sep=''.

measures = 4
beats_per_measure = 4
for measure in range(0 , measures):
for beats in range(1 , beats_per_measure + 1):
#print(beats)
if beats == 1:
beats += measure
elif beats != 1:
beats = beats
print(beats)
this is the answer I was looking for. It was a ^%^%$ conditional that helped me do it!!! Thanks for all the help can't wait to plug in all of your recommendations to see what else I can do!

Related

Need Help Understanding For loops with Variables in Python

I am going through the book Automate the Boring Stuff with Python, and need help understanding what's really happening with the code.
catNames = []
while True:
print('Enter the name of cat ' + str(len(catNames) + 1) + ' (Or enter nothing to stop.):')
name = input()
if name == '':
break
catNames = catNames + [name]
print('The cat names are:')
for name in catNames:
print(' ' + name)
now it makes sense until
for name in catNames:
print(' ' + name)
I am only used to seeing for loops with range(), and this does not make sense to me. A detailed explanation would be highly appreciated thanks
I will explain it to you on a simple example:
# You create some list of elements
list = [1, 2, 3, 9, 4]
# Using for loop you print out all the elements
for i in list:
print(i)
It will print to the console:
1
2
3
9
4
And you can also do it by using range but you have to know the length of the array:
# You create some list of elements
list = [1, 2, 3, 9, 4]
# get the list length
length = len(list)
# Iterating the index
# same as 'for i in range(len(list))'
for i in range(length):
print(list[i])
Console output will look the same as before

Finding number is present in sequence

I need to find out whether a given number is present in a given sequence. Sequence is an arithmetic progression with common difference of 2
Ex Input1 - 5, 7, 9, 11, 13, 15, . . .
for this sequence key is 19 so it is present i the sequence output would be True.
For input2 - be 4,6,8,10...
Given key is 15 so it is not present output should be False.
I have written the code but it is only working for first set of input which is odd numbers .Its failing for input2 which is even
arr = 4,6,8
n=10
b=max(arr)
l=[]
if b>n:
c=b
else:
c=n
d=arr[1]-arr[0]
for i in range(1,c+d+1,d):
l.append(i)
if n in l:
print("True")
else:
print("False")
Output 1 - True
output2 - False
You can take advantage of range's smart implementation of __contains__ to get a one-liner O(1) solution:
print(6 in range(2, 10, 2))
# True
print(5 in range(2, 10, 2))
# False
And an extreme example to show how fast and scalable this is (the size of the range does not matter):
from timeit import Timer
print(min(Timer(lambda: 1_000_000_000 in range(2, 1_000_000_003, 2)).repeat(1000, 1000)))
# 00032309999999990957

How to loop through a constantly updating list?

for i in range(0, len(list_stops)):
for j in range(1, len(list_stops[i])):
current = stops_from_stop(list_stops[i][j])
list_stops.extend(current)
for k in range(0, len(current)):
for m in range(0, len(current[k])):
list_stops_x.extend([current[k][m]])
if id_b in list_stops_x:
#rest of code
list_stops is a list of lists. Eg [[1,2,3], [4,5,6]]
list_stops_x is a single list of all the numbers in list_stops. Eg [1,2,3,4,5,6]. Basically used as a condition to enter the rest of the code with a return statement at the end, so the loop does not repeat.
I find that the loop ends after reaching the final index of the first version of list_stops, but I am constantly extending list_stops and want the loop to carry on into the extensions. So for example if I extend [7,8,9] to list_stops in the loop, if id_b is not found I still want it to loop through [7,8,9], but it stops at 6.
Note: This is only a section of the entire function, but I am quite sure the problem lies here. This is also for an introductory programming course, so a simple solution will do :) The full code is below
def find_path(stops, routes, stop_a, stop_b):
id_a = stop_a[0]
id_b = stop_b[0]
unused = unused_stops()
if id_b in list(unused):
return []
total_route = list()
all_stops = stops_from_stop(id_a)
list_stops_x = stops_from_stop_x(id_a)
list_stops = stops_from_stop(id_a)
for index in range(0, len(all_stops)):
if id_b in all_stops[index]:
return find_route(stops, routes, stop_a, stop_b)
for i in range(0, len(list_stops)):
for j in range(1, len(list_stops[i])):
current = stops_from_stop(list_stops[i][j])
list_stops.extend(current)
for k in range(0, len(current)):
for m in range(0, len(current[k])):
list_stops_x.extend([current[k][m]])
if id_b in list_stops_x:
stops_used_rev = [id_b]
last_route = list_stops[len(list_stops) - 1]
current_stop = last_route[0]
stops_used_rev += [current_stop]
for i in range(0, len(list_stops)):
if (current_stop in list_stops[i]) and (list_stops[i][0] == id_a):
stops_used_rev += [id_a]
break
elif current_stop in list_stops[i]:
current_stop = last_route[0]
stops_used_rev += [current_stop]
stops_used = stops_used_rev[::-1]
for index in range(0, len(stops_used) - 1):
total_route.extend(find_route(stops, routes, stops[stops_used[index]], stops[stops_used[index + 1]]))
return total_route
stops_from_stop finds the list stops accessible from the current stop and appends to another list. stops_from_stops_x does the same but extends instead
So the issue is that we use the range(0, len(list_stops)) if we instead use enumerate in the following way, BEWARE INFINITE LOOP, due too we keep adding elements to the list. So be careful, but this should give the desired result. I have changed some part of the code so I could run it.
Enumerate makes it possible to both get the item of the list (val) and the index that we are currently at.
list_stops = [[1,2,3], [4,5,6]]
list_stops_x = [1,2,3,4,5,6]
newer = [[7, 8, 9], [10, 11, 12]]
id_b = 9
for i, val in enumerate(list_stops):
print(val)
for j in range(1, len(list_stops[i])):
current = newer
list_stops.extend(current)
for k in range(0, len(current)):
for m in range(0, len(current[k])):
list_stops_x.extend([current[k][m]])
# if id_b in list_stops_x:
# print("id_b in")
# break
EDIT 1
in your code that was in the edit suggestion you have loops that look like the following:
for i in range(0, len(list_stops)):
...
These should be replace with the following to fix the issue
for i, val in enumerate(list_stops):
...
I have a difficult time of testing the code, but try replace the for loops with the type that i provided and let me know
Edit 2
If we keep adding to the list ofcourse it will loop infinitely unless we exit somewhere. You can see this example that I add elements to list a from list b and then remove the item. As you see from the output we loop eight times so we know it works, you should reflect such changes in your code
a = [1, 2, 3, 4]
b = [5, 6, 7, 8]
for idx, val in enumerate(a):
print("Loop Count: " + str(idx))
if b:
a.append(b[0])
b.remove(b[0])
Loop Count: 0
Loop Count: 1
Loop Count: 2
Loop Count: 3
Loop Count: 4
Loop Count: 5
Loop Count: 6
Loop Count: 7

Optimize brute force with permutations

EXPLAINING WHAT THE SCRIPT DOES
I made a python script where the goal is to balance marbles on a circular board. Marble 1 weighs 1 Unit, 2 weighs 2 Units, and so on. The goal is to find the best order so it's a balanced as possible.
PROBLEM
I also made a method that tries all the possibilities with permutations. I get a memory error if I try with more than 10 marbles (3628800 possibilites).
Is there any way to optimize the code with either multi threading/ multiprocessing, maybe a better way than permutations?
CODE
# balance_game.py
# A program used to your skills in balancing marbles on a board
from itertools import permutations
from math import cos, radians, pow, sin, sqrt
from time import time
# Checks if marbles will balance on a circular board
# Marble 1 weighs 1 unit, 2 weighs 2 units, and so on
def test_your_might(NUMBER_OF_MARBLES, marbles):
angle = 360 / NUMBER_OF_MARBLES
angles = [angle * n for n in range(1, NUMBER_OF_MARBLES + 1)]
X = []
Y = []
Fx = []
Fy = []
i = 0
for n in range(0, NUMBER_OF_MARBLES):
angle = radians(angles[i])
X.append(cos(angle))
Y.append(sin(angle))
i += 1
for n in range(0, NUMBER_OF_MARBLES):
Fx.append(X[n] * marbles[n])
for n in range(0, NUMBER_OF_MARBLES):
Fy.append(Y[n] * marbles[n])
return sqrt(pow(sum(Fx), 2) + pow(sum(Fy), 2))
def brute_force_solution(NUMBER_OF_MARBLES):
possibilities = permutations([x for x in range(1, NUMBER_OF_MARBLES + 1)])
solutions = {}
for possibility in possibilities:
possibility = list(possibility)
solution = test_your_might(NUMBER_OF_MARBLES, possibility)
solutions[str(possibility)] = solution
return solutions
# print(test_your_might(5, [5, 1, 4, 3, 2]))
t0 = time()
solutions = brute_force_solution(10)
t1 = time()
best_order = min(solutions, key=solutions.get)
lowest_score = solutions[best_order]
print(f"Lowest score: {lowest_score}\nOrder: {best_order}")
print(f"It took {t1-t0} seconds to find the best possibility")
print(f"There were {len(solutions)} possibilities")
FYI
The method is brute_force_solution
Since the bottleneck is CPU usage, multithreading won't do a lot to help here, but multiprocessing should. Not an expert but have been experimenting with parallelism recently so will have a play around and update this answer if I get anywhere. (EDIT: I have tried a number of attempts at using multiprocessing but I've only succeeded in increasing the run time!)
It might be that you need to store all solutions, but if not, one small optimisation in terms of time, but huge in terms of memory, would be to not store all the possible results and just store the best result, so you're not creating another very long array needlessly. Ideally you could calculate number of solutions directly since it only depends on NUMBER_OF_MARBLES but have included it in the function to be consistent.
def brute_force_solution(NUMBER_OF_MARBLES):
possibilities = permutations([x for x in range(1, NUMBER_OF_MARBLES + 1)])
# count the number of solutions
number_of_solutions = 0
best_solution_so_far = None
for possibility in possibilities:
number_of_solutions += 1
possibility = list(possibility)
solution = test_your_might(NUMBER_OF_MARBLES, possibility)
# If this solution is the best so far, record the score and configuration of marbles.
if (best_solution_so_far is None) or (solution < best_solution_so_far[1]):
best_solution_so_far = (str(possibility), solution)
# Return the best solution and total number of solutions tested.
return (best_solution_so_far, number_of_solutions)
t0 = time()
one_solution = brute_force_solution(11)
t1 = time()
best_order = one_solution[0][0]
best_score = one_solution[0][1]
number_of_solutions = one_solution[1]
It took a while but it ran with 11 marbles:
>>>Lowest score: 0.00021084993450850984
>>>Order: [10, 7, 3, 4, 11, 1, 8, 9, 5, 2, 6]
>>>It took 445.57227993011475 seconds to find the best possibility
>>>There were 39916800 possibilities
and was marginally quicker when run for 10 (and note that you aren't including the sorting of your results in your timing which is not needed with this new method and adds almost another second to your time to get the best solution):
Old
Lowest score: 1.608181078507726e-17
Order: [1, 7, 3, 10, 4, 6, 2, 8, 5, 9]
It took 43.81806421279907 seconds to find the best possibility
There were 3628800 possibilities
New
Lowest score: 1.608181078507726e-17
Order: [1, 7, 3, 10, 4, 6, 2, 8, 5, 9]
It took 37.06034016609192 seconds to find the best possibility
There were 3628800 possibilities

Ugly 2 dimensional list. Why?

I'm trying to figure out why my list looks ugly when printed:
alfa = []
alfa.append([])
alfa.append([])
a = 0
a = float(a)
print("Input the points, one per line as x,y.\nStop by entering an empty line.")
while a == 0:
start = input()
if start == '':
a = a + 1
else:
alfa[0].append(start.split(",")[0:1])
alfa[1].append(start.split(",")[1:2])
print(alfa)
with input of:
2,3
12,56
1,2
a
I get this:
[[['2'], ['12'], ['1']], [['3'], ['56'], ['2']]]
While if i try this simple Program found online:
elements = []
elements.append([])
elements.append([])
elements[0].append(1)
elements[0].append(2)
elements[1].append(3)
elements[1].append(4)
print(elements[0][0])
print(elements)
I get this:
[[1, 2], [3, 4]]
Why is this result much tidier than mine?
Try:
alfa[0].append(int(start.split(",")[0]))
alfa[1].append(int(start.split(",")[1]))
>>>[[2, 12, 1], [3, 56, 2]]
You're getting the quote marks because input() is interpreting the input as a string. It doesn't know that you want what you've typed to be a number, so it has to handle it in a default way. You have to tell the code that the input should be interpreted as an int.
Secondly, you're slicing the arrays when you use [0:1] to get an array consisting of the entries from 0 to 0, which is the same as getting element 0 directly, except you get an array with one element rather than just the element you want. Essentially, you are inserting [2] rather than 2.
The data from your input is strings, as shown by the quotation marks. Cast your strings to integers after the input. If you want to have the [1, 2] formatting without the extra brackets then you need to place numbers in alfa[0] and alfa[1] etc..
alfa = []
alfa.append([])
alfa.append([])
a = 0
a = float(a)
print("Input the points, one per line as x,y.\nStop by entering an empty line.")
while a == 0:
start = input()
if start == '':
a = a + 1
else:
alfa[0].append(int(start.split(",")[0]))
alfa[1].append(int(start.split(",")[1]))
print(alfa)
Oh, I see #Andrew McDowell has beat me to this. Well here you go anyway...

Resources