{"id":293,"date":"2021-05-10T11:31:23","date_gmt":"2021-05-10T10:31:23","guid":{"rendered":"https:\/\/glennrowe.net\/programmingpages\/?p=293"},"modified":"2021-05-31T12:14:33","modified_gmt":"2021-05-31T11:14:33","slug":"for-loops-and-the-range-function","status":"publish","type":"post","link":"https:\/\/glennrowe.net\/programmingpages\/2021\/05\/10\/for-loops-and-the-range-function\/","title":{"rendered":"For loops and the range() function"},"content":{"rendered":"<p>In addition to the <a href=\"https:\/\/glennrowe.net\/programmingpages\/2021\/05\/09\/while-loops\/\">while loop<\/a>, Python also provides the <code class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">for<\/code> loop. Its syntax has the form:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">for [variable] in [collection of values]:\r\n    do something for each member of the collection\r\n    do more...\r\nelse:\r\n    do something after all values in the collection have been processed\r\n<\/pre>\n<p>The [variable] is applied successively to each datum in the [collection of values] and the code in the first block is run in each case. After all the data in the collection have been processed, control passes to the <code class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">else<\/code> block (if present; it&#8217;s optional). Note that &#8216;in&#8217; is a keyword in Python, and cannot be used as a variable name.<\/p>\n<p>This is a rare instance in which a variable does not need to be initialized before it is used. The [variable] in the for statement is initialized by setting it to the first datum in the [collection of values].<\/p>\n<p>Like the while loop, a for loop can be terminated at any point by using the <code class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">break<\/code> statement. Also as with the while loop, a <code class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">continue<\/code> statement causes the remainder of the current iteration to be skipped, with control passing back to the top line of the loop, where the next element of the collection is then processed.<\/p>\n<p>The [collection of values] can be any of Python&#8217;s collective data types, including lists, tuples, sets and dictionaries. We&#8217;ll examine these data types later, although their use with for loops is straightforward: the loop just processes each element in the data type, as you&#8217;d expect.<\/p>\n<h2>The range() function<\/h2>\n<p>To illustrate for loops, we&#8217;ll use the <code class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">range()<\/code> function, as this gives a behaviour closest to what programmers in languages such as C++, C# and Java are used to. It has the syntax:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\"># Integers from 0 to stop - 1\r\nrange(stop)\r\n# Integers from start to stop - 1\r\nrange(start, stop)\r\n# Integers from start to stop - 1 in intervals of step\r\nrange(start, stop, step)\r\n<\/pre>\n<p>The first form generates an iterable object containing integers from 0 up to <code class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">stop - 1<\/code>, in intervals of 1. The second form does the same, but starts at &#8216;start&#8217; rather than 0. The last form generates integers from <code class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">start<\/code> to <code class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">stop - 1<\/code> with an interval of <code class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">step<\/code> between each pair of integers. The first two forms are just shorthand for the third, so we have <code class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">range(stop)<\/code> == <code class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">range(0, stop)<\/code> == <code class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">range(0, stop, 1)<\/code> and <code class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">range(start, stop)<\/code> == <code class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">range(start, stop, 1)<\/code>.<\/p>\n<p><code class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">range()<\/code> generates an object which can be accessed like an array of integers, so we can specify an index to access a particular element. For example, enter the following in the console:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">ran = range(3, 20, 2) \r\nran[3]<\/pre>\n<p>The range array consists of the numbers [3, 5, 7, 9, 11, 13, 15, 17, 19], so <code class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">ran[3]<\/code> has the value 9. The sequence always ends with the largest number that is strictly less than stop.<\/p>\n<p><code class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">range()<\/code> can also generate values in decreasing order if the step is a negative integer. In this case, start must be greater than stop, otherwise <code class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">range()<\/code> will give an empty array. Thus <code class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">range(10, 2, -1)<\/code> gives the array [10, 9, 8, 7, 6, 5, 4, 3]. In the decreasing sequence case, the sequence ends with the smallest number that is strictly greater than stop.<\/p>\n<p>If you want to see the complete array generated by <code class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">range()<\/code>, you need to convert it to a list. For example, typing<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">range(3, 20, 2)<\/pre>\n<p>into the console just produces <code class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">range(3, 20, 2)<\/code> as output. However, if you try this:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">ranlist = list(range(3, 20, 2))\r\nranlist<\/pre>\n<p>you&#8217;ll get the list [3, 5, 7, 9, 11, 13, 15, 17, 19] printed out.<\/p>\n<h2>Using range() with for loops<\/h2>\n<p>The <code class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">range()<\/code> function can be used to provide the [collection of values] in the for loop syntax above. There is no need to convert <code class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">range()<\/code> to a list in order to use it in a for loop; the for loop is intelligent enough to iterate through the values in the <code class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">range()<\/code> object on its own.<\/p>\n<p>Here&#8217;s an example that prints out a list of cubes for integers in a given range, and also illustrates another use of a for loop:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">print('Cube table')\r\nlimits = input('Enter start, stop, step: ')\r\nbounds = [int(i) for i in limits.split()]\r\nfor num in range(bounds[0], bounds[1] + 1, bounds[2]):\r\n    print(str(num) + ' ** 3 = ' + str(num **3))\r\nelse:\r\n    print('List finished.')<\/pre>\n<p>Line 2 reads in start, stop and step as a single string, so we need to split this string into 3 separate values and convert them to ints. There are several ways this can be done, but probably the most concise is that shown in the example, although it uses a technique called\u00a0<em>list comprehension<\/em> which we will cover in more detail when we examine lists. Basically, line 3 first uses the <code class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">split()<\/code> function in the string library to split the <code class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">limits<\/code> string. By default, <code class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">split()<\/code> splits a string at each occurrence of whitespace and returns a list of the separate pieces. These pieces are still strings, so we need to convert them to ints before they can be used in the <code class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">range()<\/code> function. The statement on line 3 uses a for loop to iterate over the elements in the split list and applies <code class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">int(i)<\/code> to each such element. By enclosing the statement in square brackets, the result of this operation is returned as a list, which is referenced by the variable bounds.<\/p>\n<p>Once the bounds list has been constructed, we use it in line 4 to provide the arguments for the <code class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">range()<\/code> function and calculate the table of cubes. When the loop finishes, control passes to the else block for the final message.<\/p>\n<h2>Exercise<\/h2>\n<p>Modify the cubes program above as follows:<\/p>\n<p>(a) The user may input 1, 2 or 3 values rather than always 3. If the user enters a single number, print out a table of cubes for numbers from 1 up to that number, in steps of 1. If the user enters 2 numbers, calculate the table of cubes from the first number up to (and including) the second, in steps of 1. If the user enters 3 positive numbers, the program should function as before.<\/p>\n<p>(b) The program should generate a table in descending order if the step variable is negative. This should occur only if the user enters 3 numbers with the last one being negative.<\/p>\n<p>(c) Replace the list comprehension (line 4 above) with an ordinary for loop that converts the numbers entered by the user from strings to ints.<\/p>\n<p>(d) The program should loop continuously allowing the user to generate as many tables as desired. Entering &#8216;quit&#8217; should terminate the program.<\/p>\n<p>(e) Check that step is not zero, since passing a zero step size into <code class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">range()<\/code> causes an error. If step is zero, skip the rest of that iteration and ask the user to try again.<\/p>\n<span class=\"collapseomatic \" id=\"id69d7185db5936\"  tabindex=\"0\" title=\"See answer\"    >See answer<\/span><span id='swap-id69d7185db5936'  class='colomat-swap' style='display:none;'>Hide answer<\/span><div id=\"target-id69d7185db5936\" class=\"collapseomatic_content \">\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">print('Cube table')\r\nwhile True:\r\n    limits = input('Enter 1, 2 or 3 ints (\\'quit\\' to exit): ')\r\n    if limits == 'quit':\r\n        break\r\n    limits = limits.split()     # Split into separate strings\r\n    numLimits = len(limits)     # Find the number of ints entered\r\n\r\n    for i in range(numLimits):  # Convert strings to ints\r\n        limits[i] = int(limits[i])\r\n\r\n    bounds = [1, 1, 1]          # Initialize the bounds list\r\n\r\n    if numLimits == 1:          # Determine start, stop and step\r\n        bounds[1] = limits[0]\r\n    elif numLimits == 2:\r\n        bounds[0] = limits[0]\r\n        bounds[1] = limits[1]\r\n    else:\r\n        bounds[0] = limits[0]\r\n        bounds[1] = limits[1]\r\n        bounds[2] = limits[2]\r\n        if bounds[2] == 0:     # If step is 0, skip this iteration\r\n            continue\r\n\r\n    if bounds[2] &lt; 0:          # Adjust stop so that a full list is printed\r\n        stop = bounds[1] - 1\r\n    else:\r\n        stop = bounds[1] + 1\r\n\r\n    for num in range(bounds[0], stop, bounds[2]):\r\n        print(str(num) + ' ** 3 = ' + str(num **3))\r\n    else:\r\n        print('List finished.')\r\n<\/pre>\n<p>Most of the code should be self-explanatory with the comments, but here&#8217;s a summary.<\/p>\n<p>The while loop on line 2 allows the user to enter as many data sets as desired. If &#8216;quit&#8217; is input, line 5 breaks out of the while loop and ends the program. Line 6 splits the input into separate strings and line 7 determines how many numbers the user entered. Lines 9 and 10 convert these into ints.<\/p>\n<p>Lines 14 through 22 sort out the values of start, stop and step that will be used in the call to <code class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">range()<\/code> in line 31. If the user entered only 1 number, then the table should go from 1 to that number, in increments of 1, so only the value of stop (<code class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">bounds[1]<\/code>) needs to be set. If 2 numbers were entered, the first is start (<code class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">bounds[0]<\/code>) and the second is stop (<code class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">bounds[1]<\/code>), while if 3 numbers were entered, we set the values of start, stop and step.<\/p>\n<p>Line 23 checks that the step size is non-zero, and line 24 skips the rest of the iteration if it is.<\/p>\n<p>Lines 26 through 29 adjust the value of stop to take account of the fact that the second argument in <code class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">range()<\/code> is non-inclusive, so we need to subtract 1 if we want a descending sequence or add 1 if we want an ascending sequence. Finally, lines 31 and 32 print out the table as before.<\/p>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>In addition to the while loop, Python also provides the for loop. Its syntax has the form: for [variable] in [collection of values]: do something for each member of the collection do more&#8230; else: do something after all values in the collection have been processed The [variable] is applied successively to each datum in the [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[4],"tags":[],"class_list":["post-293","post","type-post","status-publish","format-standard","hentry","category-python","entry"],"_links":{"self":[{"href":"https:\/\/glennrowe.net\/programmingpages\/wp-json\/wp\/v2\/posts\/293","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/glennrowe.net\/programmingpages\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/glennrowe.net\/programmingpages\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/glennrowe.net\/programmingpages\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/glennrowe.net\/programmingpages\/wp-json\/wp\/v2\/comments?post=293"}],"version-history":[{"count":6,"href":"https:\/\/glennrowe.net\/programmingpages\/wp-json\/wp\/v2\/posts\/293\/revisions"}],"predecessor-version":[{"id":299,"href":"https:\/\/glennrowe.net\/programmingpages\/wp-json\/wp\/v2\/posts\/293\/revisions\/299"}],"wp:attachment":[{"href":"https:\/\/glennrowe.net\/programmingpages\/wp-json\/wp\/v2\/media?parent=293"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/glennrowe.net\/programmingpages\/wp-json\/wp\/v2\/categories?post=293"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/glennrowe.net\/programmingpages\/wp-json\/wp\/v2\/tags?post=293"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}