I do not understand how the result is 10...
Specifically where in the function does it create the loop that adds 1, 2, 3 and 4?
I am also new to Stackoverflow, so if there is a relative article that I overlooked then please do refer me.
def func(x):
res=0
for i in range(x):
res += i
return res
print(func(5))
def func(x): # defines the function name and input parameter
res=0 # created a variable that is right now set to 0
for i in range(x): # this has two parts, for-loop, and a range function both explained below
res += i # this adds 1 to the variable 'res' each time the for-loop loops
return res # end of the function, passes the variables value back to the caller
print(func(5)) # call the function while passing 5 as an argument
This is how a for loop works,
it will loop over each element you provide it.
so,
myPets = ['dog', 'cat', 'rabbit'] # create a list of pets
for pet in myPets:
print pet # print each pet
When this runs, you get
dog
cat
rabbit
Now the range function, creates a sequence of x numbers ranging from 0 to x-1 so,
range(5)
is equivalent to:
[0,1,2,3,4]
Keep in mind, it starts at 0 and ends at x-1
we could also do
range(3, 6)
which would be equivalent to:
[3,4,5]
note that in python2 range actually returns the list where as in python3 range is a separate sequence type. For the purposes of a for loop, they do the same thing.
As mentioned in comments, you need to know what does the range function to understand that loop.
range(x) function creates an array which contains from 0 to x-1. So range(5) create the array [0, 1, 2, 3, 4]. So the loop:
for i in range(5)
it's equivalent to:
for i in [0, 1, 2, 3, 4]
for i in range(x):
This is the loop you are looking for. It iterates over every element in range(x).
When you have range(5), you are telling python to generate 5 integers, which are up to but not including 5. So they are 0, 1, 2, 3, 4.
The += operator adds right operand to the left operand and assign the result to left operand.
So in your case, with the function and the loop iterating from 0 to 4, you are telling python to generate a function called func(x); within this function, generate a range of integers, from 0 up to but not including 5; add whatever i is to res (to add 0, 1, 2, 3, 4 sequentially to res).
Finally it becomes 10.
res += i means res= res+i
so for loop loops as below
res = 0, initially
The supplied list for looping is
[0,1,2,3,4]
so res += i is applied for each element of the list
the variable 'i' is a temporary variable used to loop through the for loop function.
so value of 'i' will be changing every time it loops i.e
i=0
i=1
i=2
i=3
i=4
the value of res keeps on changing as per the for loop
res= 0+0 =0
res= 0+1 =1
res= 1+2 =3
res= 3+3 =6
res= 6+4 =10
Final returned value is 10 as for loop ends at 4 value in the list
From Python.org:
If you do need to iterate over a sequence of numbers, the built-in function range() comes in handy. It generates lists containing arithmetic progressions, e.g.:
>>> range(10)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Essentially, for i in range(10) is the same as saying for i in [1,2,3,4,5,6,7,8,9,10]
The += operator is the same as saying res = res + value
So, in combination with the range statement, this piece of code is looking at the first element of the list, 0, adding that to zero(your starting element: res = 0), then adding one to that, then adding two to the result of the previous computation (resulting in 3), and so on.
Related
I am learning Python3 and as I can see in the past, with Python2, it was possible to create a list of numbers with range() by just passing a single argument, which would be the last number of list + 1 in the list:
range(4) # == [0, 1, 2, 3]
and the start and step values were defaulted to 0 and 1.
But in Python3 for some reason, it is no longer possible to omit those 2 arguments and for the same result we would need to wrap the range() function with the list() function:
range(0, 4, 1) # == range(0, 4)
range(4) # == range(0, 4)
list(range(4)) # == [0, 1, 2, 3]
Question(s):
What is the reason behind that? Why was the functionality changed this way? Is there a good reason for that?
P.S. or maybe I am doing something incorrectly. Here, I am talking about range() function in general, whether it is being used in for-loops, just to create a list or for any other purpose
You've unfortunately been misled by the repr of range:
>>> range(4)
range(0, 4)
It is actually the same interface, but this is returning a lazily-generated sequence now, as opposed to a list. You may iterate a range instance to consume the values:
>>> list(range(4))
[0, 1, 2, 3]
See Python range() and zip() object type for more details about this change.
I am currently learning Python (I have a strong background in Matlab). I would like to write a loop in Python, where the size of the array increases with every iteration (i.e., I can assign a newly calculated value to a different index of a variable). For the sake of this question, I am using a very simple loop to generate the vector t = [1 2 3 4 5]. In Matlab, programming my desired loop would look something like this:
t = [];
for i = 1:5
t(i,1) = i;
end
I have managed to achieve the same thing in Python with the following code:
result_t = []
for i in range(1,5):
t = i
result_t.append(t)
Is there a more efficient way to assign values to an array as we iterate in Python? Why is it not possible to do t[i,1] = i (error: list indices must be integers or slices, not tuple) or t.append(t) = t (error: 'int' object has no attribute 'append')?
Finally, I have used the example above for simplicity. I am aware that if I wanted to generate the vector [1 2 3 4 5] in Python, that I could use the function "np.arange(1,5,1)"
Thanks in advance for your assistance!
-> My real intention isn't to produce the vector [1 2 3 4 5], but rather to assign calculated values to the index of the vector variable. For example:
result_b = []
b = 2
for i in range(1,5):
t = i + b*t
result_b.append(t)
Why can I not directly write t.append(t) or use indexing (i.e., t[i] = i + b*t)?
Appending elements while looping using append() is correct and it's a built-in method within Python lists.
However you can have the same result:
Using list comprehension:
result_t = [k for k in range(1,6)]
print(result_t)
>>> [1, 2, 3, 4, 5]
Using + operator:
result_t = []
for k in range(1,6):
result_t += [k]
print(result_t)
>>> [1, 2, 3, 4, 5]
Using special method __iadd__:
result_t = []
for k in range(1,6):
result_t.__iadd__([k])
print(result_t)
>>> [1, 2, 3, 4, 5]
The range function returns an iterator in modern Python. The list function converts an iterator to a list. So the following will fill your list with the values 1 to 5:
result_t = list(range(1,6)) # yields [1, 2, 3, 4, 5]
Note that in order to include 5 in the list, the range argument has to be 6.
Your last example doesn't parse unless you assign t a value before the loop. Assuming you do that, what you're doing in that case is modifying t each time through the loop, not just producing a linear range. You can get this effect using the map function:
t = 0
b = 2
def f(i):
global t
t = i + b*t
return t
result_b = list(map(f, range(1, 5))) # Yields [1, 4, 11, 26]
The map function applies the f function to each element of the range and returns an iterator, which is converted into a list using the list function. Of course, this version is more verbose than the loop, for this small example, but the technique itself is useful.
a better example from UI Testing using selenium.
print('Assert Pagination buttons displayed?')
all_spans = self.web_driver.find_elements_by_tag_name('span')
# Identify the button texts
pagination_buttons = ["Previous Page", "Next Page", "First Page"]
# Filter from all spans, only the required ones.
filtered_spans = [s for s in all_spans if s.text in pagination_buttons]
# From the filtered spans, assert all for is_displayed()
for a_span in filtered_spans:
assert a_span.is_displayed()
print('Asserted Pagination buttons displayed.')
You can try this
data = ['Order-'+str(i) for i in range(1,6)]
print(data)
>>> ['Order-1', 'Order-2', 'Order-3', 'Order-4', 'Order-5']
I was trying to execute a for loop like:
a = [1,2,3,4,5,6,7]
for i in range(0, len(a), 1):
if a[i] == 4:
a.remove(a[i])
I end up having an index error since the length of the list becomes shorter but the iterator i does not become aware.
So, my question is, how can something like that be coded? Can the range of i be updated in each iterations of the loop based on current array condition?
For the .pop() that you mention for example you can use a list comprehension to create a second list or even modify the original one in place. Like so:
alist = [1, 2, 3, 4, 1, 2, 3, 5, 5, 4, 2]
alist = [x for x in alist if x != 4]
print(alist)
#[1, 2, 3, 1, 2, 3, 5, 5, 2]
As user2393256 more generally puts it, you can generalize and define a function my_filter() which will return a boolean based on some check you implement in it. And then you can do:
def my_filter(a_value):
return True if a_value != 4 else False
alist = [x for x in alist if my_filter(x)]
I would go with the function solution if the check was too complicated to type in the list comprehension, so mainly for readability. The example above is therefore not the best since the check is very simple but i just wanted to show you how it would be done.
If you want to delete elements from your list while iterating over it you should use list comprehension.
a = [1,2,3,4,5,6,7]
a = [x for x in a if not check(x)]
You would need to write a "check" function that returns wether or not you want to keep the element in the list.
I don't know where you are going with that but this would do what I beleive you want :
i=0
a = [1,2,3,4,5,6,7]
while boolean_should_i_stop_the_loop :
if i>=len(a) :
boolean_should_i_stop_the_loop = False
#here goes what you want to do in the for loop
print i;
a.append(4)
i += 1
def counting_sort(array, maxval):
"""in-place counting sort"""
m = maxval + 1
count = [0] * m # init with zeros
for a in array:
count[a] += 1 # count occurences
i = 0
for a in range(m): # emit
for c in range(count[a]): # - emit 'count[a]' copies of 'a' #CONFUSED
array[i] = a
i += 1
return array
print counting_sort( [1, 4, 7, 2, 1, 3, 2, 1, 4, 2, 3, 2, 1], 7 )
# prints: [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 4, 4, 7]
So in the code above i dont understand the line I marked with confused, 4 lines before the last.
Might be because I am new to python or just stupid.
What happends in the first case? When the range is [ ] ? ... "for each c in the range of empty array....?
i dont get array[i] = a on the line under aswell. If a is the first element in the counting array which might be zero, how can it be added....? Really confused...
Cheers!
You've apparently figured out that count[a] will be 0, and that range(count[a]) will therefore be [].
So, what you're asking is, what does this do:
for i in []:
do_stuff(i)
The answer is that it loops over each of the 0 elements—in other words, it doesn't loop at all. It just does nothing.*
This is explained in the docs for the for statement:
… The suite is then executed once for each item provided by the iterator… When the items are exhausted (which is immediately when the sequence is empty…) … the loop terminates.
And that implicitly explains your second bit of confusion:
If a is the first element in the counting array which might be zero, how can it be added
When count[a] is 0, you will never get into the loop, so that case cannot ever arise.
* If the for statement has an else clause, it does run the else clause.
range will give you a list with specified start and end values. For example
print range(5)
will print
[0, 1, 2, 3, 4]
When you say, range(m) or range(count[a]) it will generate a list till m or count[a] starting from 0.
About array[i] = a
In the range(m), for each element, the code checks the count[a]. If the count[a] is 0, the second loop will not be executed. (range(0) will produce an empty list) So, for when a is 0 array[i] = a will not be executed.
I simplified part of you code, maybe it it can help you understand the core of the algorithm well . After counting all the elements in the array, we can reconstruct a sorted array only with the information stored in count[].
array=[]
for a in range(m):
array.extend([a]*count[a])
I want to change a in the for-loop to [4,5,6].
This code just print: 1, 2, 3
a = [1,2,3]
for i in a:
global a
a = [4,5,6]
print i
I want the ouput 1, 4, 5, 6.
You'll need to clarify the question because there is no explanation of how you should derive the desired output 1, 4, 5, 6 when your input is [1, 2, 3]. The following produces the desired output, but it's completely ad-hoc and makes no sense:
i = 0
a = [1, 2, 3]
while i < len(a):
print(a[i])
if a[i] == 1:
a = [4, 5, 6]
i = 0 # edit - good catch larsmans
else:
i += 1
The main point is that you can't modify the parameters of a for loop while the loop is executing. From the python documentation:
It is not safe to modify the sequence being iterated over in the loop
(this can only happen for mutable sequence types, such as lists). If
you need to modify the list you are iterating over (for example, to
duplicate selected items) you must iterate over a copy.
Edit: if based on the comments you are trying to walk URLs, you need more complicated logic to do a depth-first or breadth-first walk than just replacing one list (the top-level links) with another list (links in the first page). In your example you completely lose track of pages 2 and 3 after diving into page 1.
The issue is that the assignment
a = [4,5,6]
just changes the variable a, not the underlying object. There are various ways you could deal with this; one would be to use a while loop like
a = [1,2,3]
i = 0
while i<len(a):
print a[i]
a = [4,5,6]
i += 1
prints
1
5
6
If you print id(a) at useful points in your code you'll realise why this doesn't work.
Even something like this does not work:
a = [1,2,3]
def change_a(new_val):
a = new_val
for i in a:
change_a([4,5,6])
print i
I don't think it is possible to do what you want. Break out of the current loop and start a new one with your new value of a.