changing the value of iterator of for loop at certain condition in python - python-3.x

Hello friend while learning python it came into my mind that is there any way by which we can directly jump to a particular value of iterator without iterating fro example
a=range(1.10) or (1,2,3,4,5,6,7,8,9)
for i in a
print ("value of i:",i)
if (certain condition)
#this condition will make iterator to directly jump on certain value of
#loop here say if currently i=2 and after this it will directly jump the
#the iteration value of i=8 bypassing the iterations from 3 to 7 and
#saving the cycles of CPU)

There is a solution, however it involves complicating your code somewhat.
It does not require an if function however it does require both while and try loops.
If you wish to change the numbers skipped then you simply change the for _ in range() statement.
This is the code:
a = [1,2,3,4,5,6,7,8,9,10]
at = iter(a)
while True:
try:
a_next = next(at)
print(a_next)
if a_next == 3:
for _ in range(4, 8):
a_next = next(at)
a_next = str(a_next)
print(a_next)
except StopIteration:
break

The iterator interface is based on the next method. Multiple next calls are necessary to advance in the iteration for more that one element. There is no shortcut.
If you iterate over sequences only, you may abandon the interator and write an old-fashioned C-like code that allows you to move the index:
a = [1,2,3,4,5,6,7,8,9,10]
a_len = len(a)
i = 0
while i < a_len:
print(a[i])
if i == 2:
i = 8
continue
i += 1

Related

I have tried solving this problem, encountered a maximum recursion depth exceeded error

I am a bit of a noob, please go easy on me.
I'm trying to solve this.
The input I'm using.
So I have written code using mammoth amount of input and it keeps on piling up every time function is called.
I want to understand how to approach this and not get the Maximum Recursion Depth Exceeded Error
count = 0
#a #I assign the whole input here
def count_bag(x):
#a #I assign the whole input here again
for x in a:
if x == "other bags":
continue
elif "shiny gold" in a[x]:
global count
count += 1
break
else:
for y in a[x]:
count_bag(y)
count_bag(a)
print(count)
In python the recursion depth is limited for most compilers, so if you want to do some deep recursion you can use sys.setrecursionlimit(some value) to get over this issue
import sys
sys.setrecursionlimit(10**6)
Why not use a queue and skip the recursion? That way, you don't even need to use a global count variable. I haven't compiled/linted this or anything, but something like this:
def count_bag(x, a):
count = 0
to_process = list()
to_process.extend(x)
while len(to_process) > 0:
item = to_process.pop(0) # pop item off front of list
if item == 'other bags':
continue
elif 'shiny gold' in a[item]:
count += 1
else:
for y in a[item]:
to_process.extend(y)
return count

A strategy-proof method of finding the time complexity of complex algorithms?

I have a question in regard to time complexity (big-O) in Python. I want to understand the general method I would need to implement when trying to find the big-O of a complex algorithm. I have understood the reasoning behind calculating the time complexity of simple algorithms, such as a for loop iterating over a list of n elements having a O(n), or having two nested for loops each iterating over 2 lists of n elements each having a big-O of n**2. But, for more complex algorithms that implement multiple if-elif-else statements coupled with for loops, I would want to see if there is a strategy to, simply based on the code, in an iterative fashion, to determine the big-O of my code using simple heuristics (such as, ignoring constant time complexity if statements or always squaring the n upon going over a for loop, or doing something specific when encountering an else statement).
I have created a battleship game, for which I would like to find the time complexity, using such an aforementioned strategy.
from random import randint
class Battle:
def __init__(self):
self.my_grid = [[False,False,False,False,False,False,False,False,False,False],[False,False,False,False,False,False,False,False,False,False],[False,False,False,False,False,False,False,False,False,False],[False,False,False,False,False,False,False,False,False,False],[False,False,False,False,False,False,False,False,False,False],[False,False,False,False,False,False,False,False,False,False],[False,False,False,False,False,False,False,False,False,False],[False,False,False,False,False,False,False,False,False,False],[False,False,False,False,False,False,False,False,False,False],[False,False,False,False,False,False,False,False,False,False]]
def putting_ship(self,x,y):
breaker = False
while breaker == False:
r1=x
r2=y
element = self.my_grid[r1][r2]
if element == True:
continue
else:
self.my_grid[r1][r2] = True
break
def printing_grid(self):
return self.my_grid
def striking(self,r1,r2):
element = self.my_grid[r1][r2]
if element == True:
print("STRIKE!")
self.my_grid[r1][r2] = False
return True
elif element == False:
print("Miss")
return False
def game():
battle_1 = Battle()
battle_2 = Battle()
score_player1 = 0
score_player2 = 0
turns = 5
counter_ships = 2
while True:
input_x_player_1 = input("give x coordinate for the ship, player 1\n")
input_y_player_1 = input("give y coordinate for the ship, player 1\n")
battle_1.putting_ship(int(input_x_player_1),int(input_y_player_1))
input_x_player_2 = randint(0,9)
input_y_player_2 = randint(0,9)
battle_2.putting_ship(int(input_x_player_2),int(input_y_player_2))
counter_ships -= 1
if counter_ships == 0:
break
while True:
input_x_player_1 = input("give x coordinate for the ship\n")
input_y_player_1 = input("give y coordinate for the ship\n")
my_var = battle_1.striking(int(input_x_player_1),int(input_y_player_1))
if my_var == True:
score_player1 += 1
print(score_player1)
input_x_player_2 = randint(0,9)
input_y_player_2 = randint(0,9)
my_var_2 = battle_2.striking(int(input_x_player_2),int(input_y_player_2))
if my_var_2 == True:
score_player2 += 1
print(score_player2)
counter_ships -= 1
if counter_ships == 0:
break
print("the score for player 1 is",score_player1)
print("the score for player 2 is",score_player2)
print(game())
If it's just nested for loops and if/else statements, you can take the approach ibonyun has suggested - assume all if/else cases are covered and look at the deepest loops (being aware that some operations like sorting, or copying an array, might hide loops of their own.)
However, your code also has while loops. In this particular example it's not too hard to replace them with fors, but for code containing nontrivial whiles there is no general strategy that will always give you the complexity - this is a consequence of the halting problem.
For example:
def collatz(n):
n = int(abs(n))
steps = 0
while n != 1:
if n%2 == 1:
n=3*n+1
else:
n=n//2
steps += 1
print(n)
print("Finished in",steps,"steps!")
So far nobody has been able to prove that this will even finish for all n, let alone shown an upper bound to the run-time.
Side note: instead of the screen-breaking
self.my_grid = [[False,False,...False],[False,False,...,False],...,[False,False,...False]]
consider something like:
grid_size = 10
self.my_grid = [[False for i in range(grid_size)] for j in range(grid_size)]
which is easier to read and check.
Empirical:
You could do some time trials while increasing n (so maybe increasing the board size?) and plot the resulting data. You could tell by the curve/slope of the line what the time complexity is.
Theoretical:
Parse the script and keep track of the biggest O() you find for any given line or function call. Any sorting operations will give you nlogn. A for loop inside a for loop will give you n^2 (assuming their both iterating over the input data), etc. Time complexity is about the broad strokes. O(n) and O(n*3) are both linear time, and that's what really matters. I don't think you need to worry about the minutia of all your if-elif-else logic. Maybe just focus on worst case scenario?

How to break 1 cycle in a for-loop without stopping the whole loop?

I am programming a program that will make a list of all numbers from 1 to 200 that:
are not divisible by 7 or 11
do not contain the digit 7 or 11 in their number.
I want to use the pass function so when the condition is not met, it will continue with the next number. I don't really know how to do it. The pass function is probably the wrong one. I know the break function does also not work because it will end the whole loop.
Please explain me how to make this program work on this way. There are probably plenty other ways to calculate this, but the point is that i want to understand how to use the for loops better :).
n = 200 #all digits till and including 200
numbers = [] #empty list for accumulation values
for i in range(1,(n+1)):
if i%7 == 0 or i%11 == 0: #if one of these 3 conditions are met
pass #it should continue to the next number (i)
if str(7) in str(i):
pass
if str(11) in str(i):
pass
numbers.append(i)
print(numbers)
print(sum(numbers)) # for my assignment i need to sum the list
use continue in place of pass.
pass does nothing
continue skips to the next loop
so i had to use continue in my example.

Equivalent while loop block for a for loop block

I am a novice trying to learn python from Automate The Boring Stuff with Python by Al Sweigart and I came across his block of code to answer a math problem: "What is the sum of all the numbers from 0 to 100?" Apparently, this was a question Gauss got when his teacher wanted to keep him busy.
Sweigart used a for loop and range() function to get the answer:
total = 0
for num in range(101):
total=total+num
print(total)
A page later he states that "you can actually use a while loop to do the same thing as a for loop; for loops are more concise."
How would this statement be rendered in a while loop?
I tried replacing the for with while but got an error: "name 'num' is not defined." I also tried to set up a summation math equation using another block of code from another forum, but completely got lost.
print('Gauss was presented with a math problem: add up all the numbers from 0 to 100. What was the total?')
a=[1,2,3,4,5,...,100]
i=0
while i< len(a)-1:
result=(a[i]+a[i+1])/2
print(result)
i +=1
Then, I tried to setup i in an equation that would loop until each number was added, but got stuck.
print('Gauss was presented with a math problem: add up all the numbers from 0 to 100. What was the total?')
i=0
while i<101:
i=i+1
a=i
Would the while statement be too complex to warrant the effort?
Your last example comes close.
A for loop of this form:
for x in range(N):
# ...
can be replaced by a while loop like this:
x = 0
while x < N:
# ...
x += 1 # equivalent to x = x + 1
Just make sure you leave the rest of the code unchanged!
The for loop is more concise. Notice how we need a "counter" variable , in this case i with the while loop. That's not to say we don't need them in a for loop, however they're integrated nicely into the syntax to make for cleaner code.
i = 0
total = 0
while i < 101:
total += i
i += 1
print(total)
Python's for loop syntax is also a foreach equivalent:
for eachItem in list:
# Do something

How to count number of substrings in python, if substrings overlap?

The count() function returns the number of times a substring occurs in a string, but it fails in case of overlapping strings.
Let's say my input is:
^_^_^-_-
I want to find how many times ^_^ occurs in the string.
mystr=input()
happy=mystr.count('^_^')
sad=mystr.count('-_-')
print(happy)
print(sad)
Output is:
1
1
I am expecting:
2
1
How can I achieve the desired result?
New Version
You can solve this problem without writing any explicit loops using regex. As #abhijith-pk's answer cleverly suggests, you can search for the first character only, with the remainder being placed in a positive lookahead, which will allow you to make the match with overlaps:
def count_overlapping(string, pattern):
regex = '{}(?={})'.format(re.escape(pattern[:1]), re.escape(pattern[1:]))
# Consume iterator, get count with minimal memory usage
return sum(1 for _ in re.finditer(regex, string))
[IDEOne Link]
Using [:1] and [1:] for the indices allows the function to handle the empty string without special processing, while using [0] and [1:] for the indices would not.
Old Version
You can always write your own routine using the fact that str.find allows you to specify a starting index. This routine will not be very efficient, but it should work:
def count_overlapping(string, pattern):
count = 0
start = -1
while True:
start = string.find(pattern, start + 1)
if start < 0:
return count
count += 1
[IDEOne Link]
Usage
Both versions return identical results. A sample usage would be:
>>> mystr = '^_^_^-_-'
>>> count_overlapping(mystr, '^_^')
2
>>> count_overlapping(mystr, '-_-')
1
>>> count_overlapping(mystr, '')
9
>>> count_overlapping(mystr, 'x')
0
Notice that the empty string is found len(mystr) + 1 times. I consider this to be intuitively correct because it is effectively between and around every character.
you can use regex for a quick and dirty solution :
import re
mystr='^_^_^-_-'
print(len(re.findall('\^(?=_\^)',mystr)))
You need something like this
def count_substr(string,substr):
n=len(substr)
count=0
for i in range(len(string)-len(substr)+1):
if(string[i:i+len(substr)] == substr):
count+=1
return count
mystr=input()
print(count_substr(mystr,'121'))
Input: 12121990
Output: 2

Resources