Python For loop and range function - python

def countMe(num):
for i in range(0, num, 3):
print (i)
countMe(18)
def oddsOut(num1, num2):
for i in range(num1):
for j in range(num2):
print(i*j)
oddsOut(3, 8)
I don't understand how the range function works:
in countMe shouldn't the code go up till 18 ;
why is the last number printed in countMe 15, and not 18 ;
why is that in the second function oddsOut the function only counts till 7 for j and not 8 even though j is 8 ;
why is the last number printed in oddsOut 14.

well, from the help:
>>> help(range)
range(...)
range([start,] stop[, step]) -> list of integers
Return a list containing an arithmetic progression of integers.
range(i, j) returns [i, i+1, i+2, ..., j-1]; start (!) defaults to 0.
When step is given, it specifies the increment (or decrement).
For example, range(4) returns [0, 1, 2, 3]. The end point is omitted!
These are exactly the valid indices for a list of 4 elements.
so the last increment is not stop, but the last step before stop.
in countMe shouldn't the code go up till 18 ;
why is the last number printed in countMe 15, and not 18 ;
why is that in the second function oddsOut the function only founts till 7 for j and not 8 even though j is 8 ;
why is the last number printed in oddsOut 14.
more generally speaking the answer to those questions is that in most of the languages, a range is defined as [start:stop[, i.e. the last value of the range is never included, and the indexes start always at 0. The mess being that in a few languages and when working on algorithmics, ranges start at 1 and are inclusive with the last value.
In the end, if you want to include the last value you can do:
def closed_range(start, stop, step=1):
return range(start, stop+1, step)
or in your example:
>>> def countMe(num):
>>> for i in range(0, num+1, 3):
>>> print (i)
>>>
>>> countMe(18)
0
3
6
9
12
15
18
>>>

The stop parameter in a range does not include that number for example
for i in range(0,5):
print i
would print 0-4 but not 5.

Ranges in Python do not include the ending value. This is consistent with slices.
If you need a way to remember this, consider that range(10) has 10 elements - the numbers 0 through 9.

Related

Python: not printing int, only string value

print ('Hello')
for i in range(2,11,-2):
print(i)
Whats wrong with this code? I'm trying to print out :
Hello
10
8
6
4
2
but it only prints out hello. I ctrl+enter twice after print hello
If you specify a negative step in range you also have to make start bigger than stop:
for i in range(10,0,-2):
print(i)
Another way to do what you want, would be to use reversed:
for i in reversed(range(2,11,2)):
print(i)
The range() function will include the first value and exclude the second.
a = " ".join(str(i) for i in range(10, 0, -2))
print (a)
Read what range() does. First argument is a starting number, you can't start from smaller if you want to print from bigger to smaller.
You can do range(2, 11, 2) for increasingly list or range(10, 1, -2) for decreasingly.
There's also reverse range(2, 11, 2)[::-1] option, but its better to just use it as planned.
Since your range starts at 2, and ends at 11, this code won't work since you are stepping down by -2. You will have to START at 10 and then step down negatively instead of stepping down from 2. Below I have an example that gets you the output that you are seeking:
print('Hello')
for i in range(10, 1, -2):
print(i)
And here is your output:
Hello
10
8
6
4
2

What a solitaire negative number on range does?

I was doing an exercise from John Zelle's book on Python, he asked to do the Fibonacci sequence using a loop function.
After I didn't manage to get it done, I gave a look at his resolution, which was this:
n = int(input("Enter the value of n: "))
curr, prev = 1, 1
for i in range(n-2):
curr, prev = curr+prev, curr
print("The nth Fibonacci number is", curr)
While I did understand part of what he did, the part that I missed was the (n-2) range.
I gave a look here on Stackoverflow to see about this and people say that a negative number on the range goes back to the end of the list. But in this case, if the user prompts 1, the result will be range(-1).
My guess was that the author did that so that the for loop didn't sum the first two values of the Fibonacci sequence, since they are both 1, and only after the user prompts 2 and forth, the loop actually starts adding up. Am I right on my guess?
If you enter 0 or 1 for this, the code does not enter the loop, and the result is the initial value of curr, that being 1. For any higher value, the loop will iteratively compute the proper value.
Your memory of negative values is a little bit off: a negative index will work from the opposite end of an iterable (e.g. list, tuple, string). A range is not quite in that class; the result in this case is an empty range.
CLARIFICATION after OP comment
I see your confusion. range returns an iterable of the given values. However, it looks like you've confused the limits with the index. Let's work with a general form:
r = range(left, right, step)
r[pos]
left* defaults to 0; **step defaults to 1
Here are some examples:
>>> r = range(0, 20, 2)
>>> r[-1]
18
>>> r = range(0, -1)
>>> r
[]
>>> r = range(0, -10, -2)
>>> r
[0, -2, -4, -6, -8]
>>> r[-2]
-6
Note the second and third examples, where we use negative values for endpoints. There's a distinction between a negative endpoint and a negative index. The endpoint is used to build the list; if the endpoints aren't in the order implied by the step, then the resulting range is the empty list. range(0, -1) is such an example.
Once the list is built, such as with range(0, 20, 2), then a reference into that list with a negative index will count from the right end of the list. Note the third example, making a list that goes "backward", 0 down to -8. A negative index in this case also works from the right. The negative right-end value, the negative step, and the negative index are three distinct usages.
Does that clear up things?
>>> range(-1)
range(0, -1)
So the for loop is not entered if n is 1 or 2 and curr (which is set to 1) is the result.

How to explain the reverse of a sequence by slice notation a[::-1]

From the python.org tutorial
Slice indices have useful defaults; an omitted first index defaults to zero, an omitted second index defaults to the size of the string being sliced.
>>> a = "hello"
>>> print(a[::-1])
olleh
As the tutorial says a[::-1] should equals to a[0:5:-1]
but a[0:5:-1] is empty as follows:
>>> print(len(a[0:5:-1]))
0
The question is not a duplicate of explain-slice-notation. That question is about the general use of slicing in python.
I think the docs are perhaps a little misleading on this, but the optional arguments of slicing if omitted are the same as using None:
>>> a = "hello"
>>> a[::-1]
'olleh'
>>> a[None:None:-1]
'olleh'
You can see that these 2 above slices are identical from the CPython bytecode:
>>> import dis
>>> dis.dis('a[::-1]') # or dis.dis('a[None:None:-1]')
1 0 LOAD_NAME 0 (a)
3 LOAD_CONST 0 (None)
6 LOAD_CONST 0 (None)
9 LOAD_CONST 2 (-1)
12 BUILD_SLICE 3
15 BINARY_SUBSCR
16 RETURN_VALUE
For a negative step, the substituted values for None are len(a) - 1 for the start and -len(a) - 1 for the end:
>>> a[len(a)-1:-len(a)-1:-1]
'olleh'
>>> a[4:-6:-1]
'olleh'
>>> a[-1:-6:-1]
'olleh'
This may help you visualize it:
h e l l o
0 1 2 3 4 5
-6 -5 -4 -3 -2 -1
You are confused with the behavior of the stepping. To get the same result, what you can do is:
a[0:5][::-1]
'olleh'
Indeed, stepping wants to 'circle' around backwards in your case, but you are limiting it's movement by calling a[0:5:-1].
All it does is slice. You pick. start stop and step so basically you're saying it should start at the beginning until the beginning but going backwards (-1).
If you do it with -2 it will skip letters:
>>> a[::-2]
'olh'
When doing [0:5:-1] your'e starting at the first letter and going back directly to 5 and thus it will stop. only if you try [-1::-1] will it correctly be able to go to the beginning by doing steps of negative 1.
Edit to answer comments
As pointed out the documentation says
an omitted second index defaults to the size of the string being
sliced.
Lets assume we have str with len(str) = 5. When you slice the string and omit, leave out, the second number it defaults to the length of the string being sliced, in this case - 5.
i.e str[1:] == str[1:5], str[2:] == str[2:5]. The sentence refers to the length of the original object and not the newly sliced object.
Also, this answer is great
a[0:5:-1] does not make much sense, since when you use this notation the indices mean: a[start:end:step]. When you use a negative step your end value needs to be at an "earlier" position than your start value.
You'll notice that the third slice argument, the step, is not presented in the part of the tutorial you quoted. That particular snippet assumes a positive step.
When you add in the possibility of a negative step, the behavior is actually pretty intuitive. An empty start parameter refers to whichever end of the sequence one would start at to step through the whole sequence in the direction indicated by the step value. In other words it refers to the lowest index (to count up) if you have a positive step, and the highest index (to count down) if you have a negative step. Likewise, an empty end parameter refers to whichever end of the sequence one would end up at after stepping through in the appropriate direction.
The docs simply aren't correct about the default values as you've pointed out. However, they're consistent other than that minor error. You can view the docs I am referring to here: https://docs.python.org/3/library/stdtypes.html#common-sequence-operations
Note that the behavior is definitionaly correct according to the docs:
The slice of s from i to j with step k is defined as the sequence of
items with index x = i + n*k such that 0 <= n < (j-i)/k. In other
words, the indices are i, i+k, i+2*k, i+3*k and so on, stopping when j
is reached (but never including j).
When you do:
>>> a = "hello"
>>> y = a[0:5:-1]
we have that i == 0, j == 5, and k == -1. So we are grabbing items at index x = i + n*k for n starting at 0 and going up to (j-i)/k. However, observe that (j-i)/k == (5-0)/-1 == -5. There are no n such that 0 <= n < -5, so you get the empty string:
>>> y
''
Do a[start:stop][::step] when in doubt (it's almost always what we want)
It's almost always the case that when you pass a negative step to something like x[start:stop:step], what you want to happen is for the sub selection to happen first, and then just go backwards by step (i.e. we usually want x[start:stop][::step].
Futhermore, to add to the confusion, it happens to be the case that
x[start:stop:step] == x[start:stop][::step]
if step > 0. For example:
>>> x = list(range(10))
>>> x
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> x[2:6:2]
[2, 4]
>>> x[2:6][::2]
[2, 4]
>>> x[1:10][::3]
[1, 4, 7]
>>> x[1:10:3]
[1, 4, 7]
Unfortunately, this doesn't hold when step < 0, even though it's tempting to think that it should.
After being burned by this a couple times, I realized it's just safer to always do the step clause after you perform the start:stop slice. So I almost always start with y = x[start:stop][::step], at least when prototyping or creating a new module where correctness/readability is the primiary concern. This is less performant than doing a single slice, but if performance is an issue, then you can do the less readable:
y = x[start:stop:step] if step > 0 else x[stop:start:step]
HTH.
For Python slicing for a sequence[start:stop:step], have derived these rules:
start:stop = start:stop:1
start:stop:(+ or -) step - It means when traversing skip N items in the sequence. However, (-) indicates backward traversal
Remember, position of last item in sequence is -1, and the one before than is -2, and so on..
# start:stop: +step Rules
Always traverse in forward
Always start from beginning of sequence as its a positive step ( forward )
Start at requested position, stop at requested position but exclude the item stop position
Default start: If start is not provided, start at 0
Default stop: if stop is not provided, it means until the end of the sequence including the last value
If item at stop position is not reachable (item is beyond the end of sequence traversal), slice does not return anything
# start:stop:-step Rules
Always traverse in reverse
If start position is provided, start from there, but traverse in reverse ( its a step back )
If stop is provided, stop traversing there but exclude this
Default start: If start position is not provided, start position is the last position of the sequence ( since negative traversal)
Default stop: If stop is not provided, it is the beginning of the list ( position 0)
If item at stop position is not reachable (item is beyond the end of sequence traversal), slice does not return anything

Converting C style for loop to python

How do you convert a c-style for loop into python?
for (int i = m; i >= lowest; i--)
The best that I came up with was:
i = mid
for i in range(i, low,-1):
for i in range(m, low - 1, -1):
Keep in mind range is exclusive of the stop parameter.
range(...)
range(stop) -> list of integers
range(start, stop[, step]) -> list of integers
The difference between this code and the C code is that in Python 2, a list is being constructed in memory by range so for very huge ranges this could be a problem. Replacing range with xrange would not build a list in memory and make the code practically the same. In Python 3 this issue no longer exists.
m from where the loop start.
l where the loop stop, and range exclude last item so l-1 and
-1 for reverse array.
for i in range(m, l-1, -1):
m = 20
low = 10
for i in range(m, low - 1, -1):
print i
This will count down as expected:
20
19
18
17
16
15
14
13
12
11
10
range takes three parameters, a start, a stop and the increment between each step.
Where possible, the Python idiom is to loop over the items directly, not to count through them. Therefore an idiomatic way to count down would be for item in reversed(list): print item or to take a reversed slice >>> someList[m:lowest-1:-1]
If you are looping over items and also need a counter, Python has enumerate() to generate counting index numbers while looping. for index, value in enumerate(someList):
It's not always possible to do this, sometimes you are counting and not going over any other data except the numbers, and range() is fine - as the other answers suggest. But when you have a for (int i=... loop, see if you can change it to act directly on the data. Writing "C in Python" is no fun for anyone.

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

Categories

Resources