How to jump some steps when use python's for statement - python

I have an interveiw yesterday, when I write python code to achieve some algorithm, I have a question. Some logic can be achieved like this using C:
void get_some_num(int a[], int length) {
int i;
for(i = 0; i < length - 1; ++i) {
if(something) i++; // jump a num in the array
a[i] = 1;
}
return some_num;
}
C language can jump some elements(such as n) when using i += n statement in for-loop to iterate an array, but I find it's difficult to achieve by using python's for statement gracefully.
How can I do it?

If you want to do this in a way similar to C, then just use a while loop (any for loop is really just a specialization of a while loop after all):
i = 0
end = 10
while i < end:
# NOTE: do something with i here
if i == 5:
i += 3
i += 1
Or you can explicitly create and move forward the iterator (which I find a lot less readable):
it = iter(range(0, 10))
for i in it:
if i == 5:
for j in range(0, 3):
i = next(it)
print(i)

Python also supports continue to "skip steps" and continue the loop.
Using it in a for loop:
for i in range(0, 10):
if i == 5:
continue
# will never print 5
print(i)
if you are looking to make it skip a few indexes in your iteration, then you can do something like this with a while loop:
x = range(0, 10)
i = 0
while i <= len(x):
if i == 5:
i += 3
continue
print(i)
i += 1
Output:
0
1
2
3
4
8
9
10

I've never really had much need to skip more than one step, but... You can use a skip variable that you decrement every time you skip.
skip = 0
for i, item in enumerate(my_list[:-1]):
if skip:
skip -= 1
continue
if item == my_list[i+1]:
skip = 1 # or whatever n value you want
continue
# Other code

If you want to do several jumps use the mod operator %
i.e
Jump every 2
for i in range(1, 10):
if i%2 == 0:
print(i)
2
4
6
8
jump every 3
for i in range(1, 10):
if i%3 == 0:
print(i)
3
6
9
An so on.

You have to use continue
for item in loop:
if item == 'wrong':
continue

Related

How can I manually progress an iterator variable in Python 3?

I would like to know how to manually progress an iterator variable in Python3. In C, for example, if during a for loop such as:
for( int i = 0, k = 10; i < k; ++i), I could skip loop iterations when i == {2,3,4} by simply setting i from within the loop body like this: if(i == 1) i = 5;
However, when I do something like this from within a for in loop in Python3, the for in loop actually enforces that I cannot do this - it mutates i and sets it to the next sequential number regardless of what I did to the iterator variable in the loop body.
For example in the Python3 code below, I am trying to progress i to the position of j such that I can skip i to the end of the group of spaces once the algorithm has detected a group of spaces:
testString = "This is a testzstring"
# find length and end of each space group
spacePositionsAndLengths = {}
j = 0
length = len(testString)
for i in range(length):
if testString[i] == " ":
j = i # mark beginning of spaces
while j < length and testString[j] == " ":
j += 1
# j-1 is now the last space. Alternatively, j is at first non-space
lengthOfSpaces = j-i
print(f"i: {i}\t lengthOfSpaces: {lengthOfSpaces}")
spacePositionsAndLengths[i] = lengthOfSpaces
i = j # remember, at this point j is at first non-space
print(testString)
That algorithm prints this output when run with:
i: 4 lengthOfSpaces: 1
i: 7 lengthOfSpaces: 1
i: 9 lengthOfSpaces: 3
i: 10 lengthOfSpaces: 2
i: 11 lengthOfSpaces: 1
This is a testzstring
This is decent, but what I want is it to print this:
i: 4 lengthOfSpaces: 1
i: 7 lengthOfSpaces: 1
i: 9 lengthOfSpaces: 3
This is a testzstring
I do not want the redundant 3..2..1 "countdown" style space counting.
Note: I am not building a production application; I am working on algorithms and the instructions require me to NOT use many of the builtin string methods. I note this because I expect comments saying "Why don't you just use X, Y, or Z builtin function and be done with this whole thing in 1 line??"
To manually progress the iterator, you need access to it. You can explicitly create the iterator yourself and then both give it to the for statement and treat it yourself as you wish. Example:
irange = iter(range(10))
for i in irange:
print(i)
next(irange)
Output:
0
2
4
6
8
Though in your example, a while loop might be better.
What you need is a while loop so that you can have your own iterator that you can mutate. It may look something like.
j = 0
i = 0
length = len(testString)
while i < length:
if testString[i] == " ":
j = i # mark beginning of spaces
while j < length and testString[j] == " ":
j += 1
# j-1 is now the last space. Alternatively, j is at first non-space
lengthOfSpaces = j-i
print(f"i: {i}\t lengthOfSpaces: {lengthOfSpaces}")
spacePositionsAndLengths[i] = lengthOfSpaces
i = j # remember, at this point j is at first non-space
i += 1

traversing through a list using recursion

So I am new to recursion and I am trying to make a program where you can enter a list and python tests each integer (lets say 9 for example) and sees if the integer following it is doubled. So if I entered a list of 2 4 8 16 32, would return 4, and -5 -10 0 6 12 9 36, would return 2 because -5 followed by -10 is one and 6 followed by 12 is the second. This is the code I have so far. I feel like I am very close. but just a few thing stand in my way. Any help would be great!
L = []
def countDouble(L):
x = input(f'Enter a list of numbers separated by a space: ')
y = (x.split(' '))
print(y[1])
print(y[0])
count = 0
y[0] += y[0]
# unsure of how to multiple y[0] by 2
if y[0]*2 == y[1]:
count += 1
else:
count += 0
#how would I traverse through the rest of the entered list using recursion?
print(count)
countDouble(L)
If you want/need to solve it using recursion, the following will do the trick:
def count_sequential_doubles(li, count=0):
return count_sequential_doubles(li[1:], count + int(li[0] * 2 == li[1])) if len(li) > 1 else count
I would suggest this recursive way:
def countDouble(L):
count = 0
if len(L) == 1:
return count
else:
if int(L[0])*2 == int(L[1]):
count += 1
return count + countDouble(L[1:])
x = input(f'Enter a list of numbers separated by a space: ')
y = (x.split(' '))
count = countDouble(y)
print(count)
I urge you to read the entire answer, but in case you are not interested in tips, notes and the process of finding the solution, here are two solutions:
solution using recursion (not recommended):
x = input()
y = x.split(' ')
count = 0
def countDouble(i):
if(i+1 == len(y)):
return 'recursion ends here when'
if(int(y[i])*2==int(y[i+1])):
count += 1
countDouble(i+1)
countDouble(0)
print(count)
this solution just imitates a while loop:
solution using a while loop (recommended):
x = input()
y = x.split(' ')
count = 0
i = 0
while(i < len(y) - 1):
if(int(y[i]) * 2 == int(y[i+1])):
count += 1
i += 1
print(count)
Before I continue, here are a few tips and notes: (some of them will only make sense after)
I assume the 14 in your example is a typo
I didn't put the code in a function because it's not needed, but you can change it easily.
In your code, you are passing L as a parameter to the countDouble() function, but you don't use it. if you don't need a parameter don't pass it.
when splitting the input, the values of the list are still strings. so you have to invert them to integers (for instance, you can do that with the int() 'function') before comparing their values - otherwise multiplying by 2 will just repeat the string. for example: '13'*2 is the string '1313'
I don't know why you why you added y[0] to itself in line 9, but based on the code that comes after this would yield incorrect results, you don't need to change the elements in order to get their value multiplied by 2.
notice that in the else block, nothing has changed. adding 0 to the count doesn't change it. so you can remove the else block entirely
While it's possible to solve the problem in recursion, there's something else designed for these kind of problems: loops.
The problem is essentially repeating a simple check for every element of a list.
This is how I would arrive to a solution
so we want to run the following 'code':
if(y[0]*2 == y[1]):
count += 1
if(y[1]*2 == y[2]):
count += 1
if(y[2]*2 == y[3]):
count += 1
...
of course the computer doesn't understand what "..." means, but it gives us an idea to the pattern in the code. now we can do the following:
divide the extended 'code' into similar sections.
identify the variables in the pattern - the values that change between sections
find the starting values of all variables
find a pattern in the changes of each variable
find a breaking point, a condition on one of the variables that tells us we have reached the last repeating section.
here are the steps in this specific problem:
the sections are the if statements
the variables are the indexes of the elements in y we compare
the first index starts at 0 and the second at 1
both indexes increase by one after each if-statement
when the second index is bigger then the last index of y then we already checked all the elements and we can stop
so all is left is to set the needed variables, have a while loop with the breaking condition we found, and in the while loop have the general case of the repeating sections and then the changing of the variables.
so:
x = input(f'Enter a list of numbers separated by a space: ')
y = (x.split(' '))
count = 0
# setting the starting values of the variables
index1 = 0
index2 = 1
# creating a loop with the breaking condition
while(index2 < len(y)):
# the general case of the repeated code:
if(int(y[index1]) * 2 == int(y[index2])):
count += 1
# changing the variables for the next loop
index1 += 1
index2 += 1
print(count)
We see that the index2 is just index1 + 1 at all time. so we can replace it like that:
x = input(f'Enter a list of numbers separated by a space: ')
y = (x.split(' '))
count = 0
index1 = 0
while(index1 + 1 < len(y)):
if(int(y[index1]) * 2 == int(y[index1 + 1])):
count += 1
index1 += 1
print(count)
Note: You can use a for loop similarly to the while loop
So in summary, you can use recursion to solve the problem, but the recursion would just be imitating the process of a loop:
in each call, the breaking condition will be checked, the repeated code would run and the variables/parameters would change.
Hope you find this answer useful :)
Final edit: OP edited his example so my other code didnt apply
Some good questions people are asking, but in the spirit of helping, here's a recursive function that returns the count of all doubles.
def get_doubles_count_with_recursion(a_list, count, previous=None):
while a_list:
try:
first = previous if previous else a_list.pop(0)
next_item = a_list.pop(0)
except IndexError:
return count
if next_item / 2 == first:
count += 1
return get_doubles_count_with_recursion(a_list, count, next_item)
return count
a_list = [1, 3, 5, 10, 11, 14, 28, 56, 88, 116, 232, 464, 500]
doubles = get_doubles_count_with_recursion(a_list, 0)
print(doubles == 5)
Probably could clean it up a bit, but it's a lot easier to read than the other guy's ;)
If I'm reading your question right, you want a count of all pairs where the 2nd item is double the first. (and the 14 in the first list is a typo). In which case a simple function like this should do the job:
#a = [2,4,8,16,32]
a = [-5, -10, 0, 16, 32]
count = 0
for i, x in enumerate(a):
# Stop before the list overflows
if i < len(a) - 1:
# If the next element is double the current one, increment the counter
if a[i+1] == x * 2:
count = count + 1
else:
break
print(count)

restarting for cycle iterating over list python3

[python] 3.6
Hello, I was trying to iterate over a list with a for cycle, where I had to restart the cycle whenever a condition was confirmed.
In C I would do:
for(i = 0; i < 10; i++){
if(list[i] == something)
i = 0;
}
Here I was trying to do this:
for x in listPrimes:
if((num % x) == 0):
num /= x # divide by the prime
factorials.append(x)
x = 2 # reset to the first prime in the list?
which doesn't work correctly. What are the ways to reset the for to a certain iteration of the list? Do I have to do the for in some other way?
Thanks for your time
You could just use a while loop:
i = 0
while i < 10:
print("do something", i)
if random.random() < 0.2:
print("reset")
i = -1
i += 1
Specific to your example:
i = 0
while i < len(listPrimes):
x = listPrimes[i]
if num % x == 0:
num /= x
factorials.append(x)
i = -1
i += 1
You can use a while loop similarly to your C code.
while i < 10:
if list[i] == something:
i = 0
i += 1
Use itertools.takewhile util
Here is a contrived example:
import itertools
li = [1,2,3,4,5]
for i in range(1, 6):
print(list(itertools.takewhile(lambda x: x!=i, li)))
print("new cycle")
Output:
[]
new cycle
[1]
new cycle
[1, 2]
new cycle
[1, 2, 3]
new cycle
[1, 2, 3, 4]
new cycle
The while loop is the most elegant solution. Just for completeness you could wrap your list into custom generator and let this new iterable receive signal to reset the loop.
import time
def resetable_generator(li):
while True:
for item in li:
reset = yield item
if reset:
break
else:
raise StopIteration
x = range(10)
sum = 0
r = resetable_generator(x)
for item in r:
time.sleep(1)
sum += item
if item == 6:
sum += r.send(True)
print(sum)

While loop vs a for loop in finding sum of multiples of 3 and 5 under 1000

not really familiar with while loops but I thought it was an alternative so this may be an elementary mistake.
I need to look for the sum of natural numbers under 1000 that are multiples of 3 and 5. E.g for under 10
multiples of 3 and 5 < 10 = 3,5,6,9
sum = 23
My code using a for loop works and is as follows (this was my initial solution):
def multiple():
lst = []
for x in range(334): #didn't know how else to use a for loop but to find the largest value of x using a calculator
if 3*x < limit:
lst.append(3*x)
if 5*x< 1000:
lst.append(5*x)
if (3*x > 1000) and (5*x > 1000): #unnecessary in a forloop with a range but this is just to maintain symmetry with while loop
break
lst2 = list(set(lst)) #remove duplicates
print(sum(lst2))
multiple()
My code using a while loop(this solution doesn't even come out in te console --> maybe this is were the error lies):
def multiple():
lst = []
while True:
x = 1
if 3*x < 1000:
lst.append(3*x)
if 5*x< 1000:
lst.append(5*x)
if (3*x > 1000) and (5*x > 1000):
break
x += 1
lst2 = list(set(lst)) #remove duplicates
print(sum(lst2))
multiple()
Desired output:
233168
In addition to how to rectify the while loop, any improvements on my for loop or while loop would also be welcome. Thanks
Critically Debugging
Since you're new, let's take this opportunity to analyze the bug before we solve it. Note first that you did not notice any printouts at all. Therefore, your print() statement was either not running, or was printing only spaces. We can rule out the latter since sum() will return an integer.
Therefore, the print() is never run. The function is defined and called correctly, so that's not the issue. Now notice while True:; this is an early warning sign. If the while loop never ends, the print() will never run. We do notice there are multiple break statements that should stop the loop, but it's likely there's an issue with them.
Now we check how the loop updates. First, note the i+=1. That seems right. However, i=1 is also within the while loop. This cannot be correct, since every iteration i will be reset. This would cause the loop to run forever.
This type of critical analysis of code is only built through practice, but hopefully this answer offers some insight into how you could have fixed this issue yourself (and how I looked through your code).
Also note that adding print statements into the while loop to test would have allowed you to notice that i was always 1.
Working Code
def multiple():
lst = []
x = 1 # moved from line below
while True:
# x = 1 should not go here
if 3*x < 1000:
lst.append(3*x)
if 5*x< 1000:
lst.append(5*x)
if (3*x > 1000) and (5*x > 1000):
break
x += 1
lst2 = list(set(lst)) #remove duplicates
print(sum(lst2))
multiple()
A fairly straight forward approach is to iterate over every number from 1 to 1000 and check if it is divisible by 3 or 5, and then sum them all up.
total = sum(x for x in range(1, 1001) if x%3 == 0 or x%5 == 0)
total
# returns:
234168
Another solution:
Using for loop:
def multiple():
sum = 0
for _ in xrange(1, 1001):
if _ % 3 == 0 or _ % 5 == 0:
sum += _
return sum
print(multiple())
Using while loop:
def multiple():
sum = 0
cnt = 1
while cnt <= 1000:
if cnt % 3 == 0 or cnt % 5 == 0:
sum += cnt
cnt += 1
return sum
print(multiple())
output:
234168
#!/usr/bin/env python
def multiple():
lst = []
x=1
while (3*x < 1000) or (5*x < 1000):
if 3*x < 1000:
lst.append(3*x)
if 5*x < 1000:
lst.append(5*x)
x += 1
lst2 = list(set(lst)) #remove duplicates
print(sum(lst2))
multiple()

Python: while loop inside else

def is_prime(x):
count = 1
my_list = []
while count > 0 and count < x:
if x % count == 0:
my_list.append(x/count)
count += 1
return my_list
my_list = is_prime(18)
def prime(x):
my_list2 = []
for number in my_list:
if number <= 2:
my_list2.append(number)
else:
count = 2
while count < number:
if number % count == 0:
break
else:
my_list2.append(number)
count += 1
return my_list2
print prime(18)
Just started out with Python. I have a very simple question.
This prints: [9, 3, 2].
Can someone please tell me why the loop inside my else stops at count = 2? In other words, the loop inside my loop doesn't seem to loop. If I can get my loop to work, hopefully this should print [2, 3]. Any insight is appreciated!
Assuming that my_list2 (not a very nice name for a list) is supposed to contain only the primes from my_list, you need to change your logic a little bit. At the moment, 9 is being added to the list because 9 % 2 != 0. Then 9 % 3 is tested and the loop breaks but 9 has already been added to the list.
You need to ensure that each number has no factors before adding it to the list.
There are much neater ways to do this but they involve things that you may potentially find confusing if you're new to python. This way is pretty close to your original attempt. Note that I've changed your variable names! I have also made use of the x that you are passing to get_prime_factors (in your question you were passing it to the function but not using it). Instead of using the global my_list I have called the function get_factors from within get_prime_factors. Alternatively you could pass in a list - I have shown the changes this would require in comments.
def get_factors(x):
count = 1
my_list = []
while count > 0 and count < x:
if x % count == 0:
my_list.append(x/count)
count += 1
return my_list
# Passing in the number # Passing in a list instead
def get_prime_factors(x): # get_prime_factors(factors):
prime_factors = []
for number in get_factors(x): # for number in factors:
if number <= 2:
prime_factors.append(number)
else:
count = 2
prime = True
while count < number:
if number % count == 0:
prime = False
count += 1
if prime:
prime_factors.append(number)
return prime_factors
print get_prime_factors(18)
output:
[3, 2]
Just to give you a taste of some of the more advanced ways you could go about doing this, get_prime_factors could be reduced to something like this:
def get_prime_factors(x):
prime_factors = []
for n in get_factors(x):
if n <= 2 or all(n % count != 0 for count in xrange(2, n)):
prime_factors.append(n)
return prime_factors
all is a built-in function which would be very useful here. It returns true if everything it iterates through is true. xrange (range on python 3) allows you to iterate through a list of values without manually specifying a counter. You could go further than this too:
def get_prime_factors(x):
return [n for n in get_factors(x) if n <= 2 or all(n % c != 0 for c in xrange(2, n))]

Categories