Pythonic way to iterate through a range starting at 1 - python

Currently if I want to iterate 1 through n I would likely use the following method:
for _ in range(1, n+1):
print(_)
Is there a cleaner way to accomplish this without having to reference n + 1 ?
It seems odd that if I want to iterate a range ordinally starting at 1, which is not uncommon, that I have to specify the increase by one twice:
With the 1 at the start of the range.
With the + 1 at the end of the range.

From the documentation:
range([start], stop[, step])
The start defaults to 0, the step can be whatever you want, except 0 and stop is your upper bound, it is not the number of iterations. So declare n to be whatever your upper bound is correctly and you will not have to add 1 to it.
e.g.
>>> for i in range(1, 7, 1): print(i)
...
1
2
3
4
5
6
>>> for i in range(1, 7, 2): print(i)
...
1
3
5
A nice feature, is that it works in reverse as well.
>>> for i in range(7, 0, -1): print(i)
...
7
6
5
4
3
2
1
If you aren't using it as an index but for something that can have positive or negative values, it still comes in handy:
>>> for i in range(2, -3, -1): print(i)
...
2
1
0
-1
-2
>>> for i in range(-2, 3, 1): print(i)
...
-2
-1
0
1
2

range(1, n+1) is not considered duplication, but I can see that this might become a hassle if you were going to change 1 to another number.
This removes the duplication using a generator:
for _ in (number+1 for number in range(5)):
print(_)

for i in range(n):
print(i+1)
This will output:
1
2
...
n

Not a general answer, but for very small ranges (say, up to five), I find it much more readable to spell them out in a literal:
for _ in [1,2,3]:
print _
That's true even if it does start from zero.

range(1, n+1) is common way to do it, but if you don't like it, you can create your function:
def numbers(first_number, last_number, step=1):
return range(first_number, last_number+1, step)
for _ in numbers(1, 5):
print(_)

Related

Nested loop not printing the first element but going to 2nd element?

I have a very simple piece of code but it's driving me nuts to understand the logic.
for a in range(6):
print("\t\t")
for j in range(a):
print(a, end=" ")
The output is:
1
2 2
3 3 3
4 4 4 4
5 5 5 5 5
the first value to be printed is supposed to be 0 since the range(6) starts from 0 and a and j wrapped in for loops both are supposedly getting 0 as first element but it starts from 1 instead.
That comes, because the for loop in range 0 will not be executed. You can not execute something if that has to go 0 times. To make it run as you would like to be, you would have to write following code:
for a in range(6):
print("\t\t")
for j in range(a + 1):
print(a, end=" ")
The value of a is the number of iterations of the inner loop. (Note that the question should have the j loop indented, so that it is inside the a loop, in order to get the output shown.)
On the first iteration, a is 0, and then range(0) will give an empty sequence, which give zero iterations when iterating over it. (Specifically a StopIteration will occur the first time a value is fetched.)
On the next iteration of the outer loop, there will be one j value when iterating, and so forth.
So 0 is printed 0 times (i.e. not at all), then 1 is printed once, 2 is printed twice, ... , 5 is printed 5 times.
You are not using the values of j at all, but they will be:
when a is 0: no iterations
when a is 1: j is 0 only
when a is 2: j is 0, 1
... etc, up to ...
when a is 6: j is 0, 1, 2, 3, 4, 5
Note that in fact it is conventional to use a variable name _ for a loop variable whose value you do not use (at least assuming that it not inside a loop already using _). If you adhere to this convention (i.e. use _ instead of j) and also fix the indentation, then your code might look like:
for a in range(6):
print("\t\t")
for _ in range(a):
print(a, end=" ")

Python-why does it print out "dessert"

I'm new to programming, and obviously I can easily run a program to get the answer, but I want to get a clearer and better understanding of why this code runs "dessert". I understand len(s) is the length of the number, but what about the three numbers "-1, 0 -1"? Can I get a detailed explanation of why this prints dessert?
s = "stressed"
for i in range(len(s)-1, 0, -1):
print(s[i], end = " ")
s t r e s s e d
0 1 2 3 4 5 6 7
range function : range(start, stop, step)
len(s) = 8
len(s-1)= 7
the loop starts at 7 stops at 0 and counts(steps) bacwards by 1 (-1)
so , the loop prints
7 6 5 4 3 2 1
d e s s e r t
The code creates a range that counts down. Starting at len(s) - 1 (so 7, stressed is 8 characters long), it'll count down to 1 (the end point is not included). In other words, you are giving range() three arguments, len(s) - 1 is one argument, 0 is the second and -1 is the third, and they represent the start, stop and step arguments. See the range() type documentation.
The code then uses those values to index s; s[7] is the last character in the string, d, then s[6] is the one-but last character e, etc.
Breaking this down to the components in an interactive session:
>>> s = "stressed"
>>> len(s)
8
>>> len(s) - 1
7
>>> list(range(7, 0, -1))
[7, 6, 5, 4, 3, 2, 1]
>>> s[7]
'd'
>>> s[6]
'e'
>>> s[1]
't'
If you wanted the code to print out desserts (with the s at the end) then you need to adjust the range() to loop up to -1:
for i in range(len(s) - 1, -1, -1):
It's all about range().
It's all discussed here.
It can be used in three ways;
range(stop)
range(start, stop)
range(start, stop, step)
Where in the first case, it will give [1, 2, 3, ... stop-1], in the second case [start, start+1, start+2, ... stop-1], and in the third case [start, start+step, start+2*step, ...stop-step].
The thing to note here is that the range you get is [start, stop). Where standard interval notation has been used.
The other thing to note here is that step can be negative, which is what you have in your example.
range(len(s)-1, 0, -1)
reange(start_index, to_end_index, is_increment or is_decrement)
You call a loop with its start index, then tell it to traverse to end index and lastly increase the index or decrease the index
range(len(s)-1 *calculate the lengthof array (string), 0 *end point of traversing, -1 decrement the index)
If you use
range(0, len(s),1)
The loop will start from 0 index and traverse till last index with 1 index increment

Error i not defined in for loop using python

I have one array 'barray' of size 'bsize' and another 'carray' of size 'csize'.
The i loop is for barray and j loop is for carray.
I get an error that i is not defined. I want the loops to go from 0 to bsize - 2 in steps of 3, and 0 to csize - 2 in single steps.
How should I relate the size and array to the for loop?
bsize = 960
csize = 960
barray = bytearray(fi.read())
carray= bytearray(f1.read())
for i in range (bsize-2,i+3):
for j in range (csize-2,j+1):
for i in range (0, bsize - 2, 3): #possibly bsize - 1?
for j in range (csize - 2): # possibly csize - 1?
#do your thing
That will loop through the first one incrementing i by 3 every time, and j by 1.
Look at this tutorial or these docs to learn range, it's really useful!
I'm not sure if you want to go through bsize - 2 or just up to it. If through, use size - 1 to get size - 2.
The reason you're getting an error is that you haven't defined the i you're using in the step. As you can see, python's range isn't like a lot of other languages' for constructs. Once you get used to it, though, it's really flexible and easy to use.
Some examples using simple range:
>>> for i in range(0, 14, 3):
... print i
...
0
3
6
9
12
>>> for i in range(1, 5):
... print i
...
1
2
3
4
>>> for i in range(5):
... print i
...
0
1
2
3
4

Formulation of a recursive solution (variable for loops)

Please consider the below algorithm:
for(j1 = n upto 0)
for(j2 = n-j1 upto 0)
for(j3 = n-j1-j2 upto 0)
.
.
for (jmax = n -j1 - j2 - j_(max-1))
{
count++;
product.append(j1 * j2 ... jmax); // just an example
}
As you can see, some relevant points about the algo snippet above:
I have listed an algorithm with a variable number of for loops.
The result that i calculate at each innermost loop is appended to a list. This list will grow to dimension of 'count'.
Is this problem a suitable candidate for recursion? If yes, i am really not sure how to break the problem up. I am trying to code this up in python, and i do not expect any code from you guys. Just some pointers or examples in the right direction. Thank you.
Here is an initial try for a sample case http://pastebin.com/PiLNTWED
Your algorithm is finding all the m-tuples (m being the max subscript of j from your pseudocode) of non-negative integers that add up to n or less. In Python, the most natural way of expressing that would be with a recursive generator:
def gen_tuples(m, n):
if m == 0:
yield ()
else:
for x in range(n, -1, -1):
for sub_result in gen_tuples(m-1, n-x):
yield (x,)+sub_result
Example output:
>>> for x, y, z in gen_sums(3, 3):
print(x, y, z)
3 0 0
2 1 0
2 0 1
2 0 0
1 2 0
1 1 1
1 1 0
1 0 2
1 0 1
1 0 0
0 3 0
0 2 1
0 2 0
0 1 2
0 1 1
0 1 0
0 0 3
0 0 2
0 0 1
0 0 0
You could also consider using permutations, combinations or product from the itertools module.
If you want all the possible combinations of i, j, k, ... (i.e. nested for loops)
you can use:
for p in product(range(n), repeat=depth):
j1, j2, j3, ... = p # the same as nested for loops
# do stuff here
But beware, the number of iterations in the loop grows exponentially!
the toy example will translate into a kind of tail recursion so, personally, i wouldn't expect a recursive version to be more insightful for code review and maintenance.
however, to get acquainted to the principle, attempt to factor out the invariant parts / common terms from the individual loop and try to identify a pattern (and best prove it afterwards!). you should be able to fix a signature of the recursive procedure to be written. flesh it out with the parts inherent to the loop body/ies (and don't forget the termination condition).
Typically, if you want to transform for loops into recursive calls, you will need to replace the for statements with if statements. For nested loops, you will transform these into function calls.
For practice, start with a dumb translation of the code that works and then attempt to see where you can optimize later.
To give you an idea to try to apply to your situation, I would translate something like this:
results = []
for i in range(n):
results.append(do_stuff(i, n))
to something like this:
results = []
def loop(n, results, i=0):
if i >= n:
return results
results.append(do_stuff(i, n))
i += 1
loop(n, results, i)
there are different ways to handle returning the results list, but you can adapt to your needs.
-- As a response to the excellent listing by Blckgnht -- Consider here the case of n = 2 and max = 3
def simpletest():
'''
I am going to just test the algo listing with assumption
degree n = 2
max = dim(m_p(n-1)) = 3,
so j1 j2 and upto j3 are required for every entry into m_p(degree2)
Lets just print j1,j2,j3 to verify if the function
works in other general version where the number of for loops is not known
'''
n = 2
count = 0
for j1 in range(n, -1, -1):
for j2 in range(n -j1, -1, -1):
j3 = (n-(j1+j2))
count = count + 1
print 'To calculate m_p(%d)[%d], j1,j2,j3 = ' %(n,count), j1, j2, j3
assert(count==6) # just a checkpoint. See P.169 for a proof
print 'No. of entries =', count
The output of this code (and it is correct).
In [54]: %run _myCode/Python/invariant_hack.py
To calculate m_p(2)[1], j1,j2,j3 = 2 0 0
To calculate m_p(2)[2], j1,j2,j3 = 1 1 0
To calculate m_p(2)[3], j1,j2,j3 = 1 0 1
To calculate m_p(2)[4], j1,j2,j3 = 0 2 0
To calculate m_p(2)[5], j1,j2,j3 = 0 1 1
To calculate m_p(2)[6], j1,j2,j3 = 0 0 2
No. of entries = 6

python for increment inner loop

How to increment the outer iterator from the inner loop?
To be more precise:
for i in range(0,6):
print i
for j in range(0,5):
i = i+2
I am getting
0
1
2
3
4
5
, but I want 0,2,4
Above is the simpilfied idea what I want to acheive.
Here is my Java code:
str1="ababa"
str2="aba"
for(int i =0; i < str1.length; i++)
for(int j =0; j < str2.length; j++)
if str1[i+j]!=str[j]
break;
if( j ==str2.length -1)
i=i+str2.length;
It seems that you want to use step parameter of range function. From documentation:
range(start, stop[, step]) This is a versatile function to create
lists containing arithmetic progressions. It is most often used in for
loops. The arguments must be plain integers. If the step argument is
omitted, it defaults to 1. If the start argument is omitted, it
defaults to 0. The full form returns a list of plain integers [start,
start + step, start + 2 * step, ...]. If step is positive, the last
element is the largest start + i * step less than stop; if step is
negative, the last element is the smallest start + i * step greater
than stop. step must not be zero (or else ValueError is raised).
Example:
>>> range(10) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> range(1, 11) [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> range(0, 30, 5) [0, 5, 10, 15, 20, 25]
>>> range(0, 10, 3) [0, 3, 6, 9]
>>> range(0, -10, -1) [0, -1, -2, -3, -4, -5, -6, -7, -8, -9]
>>> range(0) []
>>> range(1, 0) []
In your case to get [0,2,4] you can use:
range(0,6,2)
OR in your case when is a var:
idx = None
for i in range(len(str1)):
if idx and i < idx:
continue
for j in range(len(str2)):
if str1[i+j] != str2[j]:
break
else:
idx = i+j
You might just be better of using while loops rather than for loops for this. I translated your code directly from the java code.
str1 = "ababa"
str2 = "aba"
i = 0
while i < len(str1):
j = 0
while j < len(str2):
if not str1[i+j] == str1[j]:
break
if j == (len(str2) -1):
i += len(str2)
j+=1
i+=1
In python, for loops iterate over iterables, instead of incrementing a counter, so you have a couple choices. Using a skip flag like Artsiom recommended is one way to do it. Another option is to make a generator from your range and manually advance it by discarding an element using next().
iGen = (i for i in range(0, 6))
for i in iGen:
print i
if not i % 2:
iGen.next()
But this isn't quite complete because next() might throw a StopIteration if it reaches the end of the range, so you have to add some logic to detect that and break out of the outer loop if that happens.
In the end, I'd probably go with aw4ully's solution with the while loops.
I read all the above answers and those are actually good.
look at this code:
for i in range(1, 4):
print("Before change:", i)
i = 20 # changing i variable
print("After change:", i) # this line will always print 20
When we execute above code the output is like below,
Before Change: 1
After change: 20
Before Change: 2
After change: 20
Before Change: 3
After change: 20
in python for loop is not trying to increase i value. for loop is just assign values to i which we gave. Using range(4) what we are doing is we give the values to for loop which need assign to the i.
You can use while loop instead of for loop to do same thing what you want,
i = 0
while i < 6:
print(i)
j = 0
while j < 5:
i += 2 # to increase `i` by 2
This will give,
0
2
4
Thank you !
for a in range(1):
for b in range(3):
a = b*2
print(a)
As per your question, you want to iterate the outer loop with help of the inner loop.
In outer loop, we are iterating the inner loop 1 time.
In the inner loop, we are iterating the 3 digits which are in the multiple of 2, starting from 0.
Output:
0
2
4

Categories

Resources