{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Loops" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In `Julia` there are two types of loops, `for` and `while`.\n", "As of `Julia 1.5` ([here](https://docs.julialang.org/en/v1/manual/variables-and-scoping/) you can find a longer discussion on the implemented changes), the behavior of those loops are very similar to loops known in other programming languages.\n", "\n", "`for` loops repeat a finite number evaluations, which is equal to the number of elements of the provided iterable object. \n", "Ranges and arrays are examples of iterable objects.\n", "One very simple `for` loop:\n", "\n", "`````{margin}\n", "````{note}\n", "Instead of `in` we can also use `∈` (`\\in` and `<tab>`) to get exactly the same results:\n", "\n", "```\n", "for i ∈ [1 2 3 4]\n", " println(\"$i=i\")\n", "end\n", "```\n", "````\n", "`````" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "i=1\n", "i=2\n", "i=3\n", "i=4\n" ] } ], "source": [ "for i in [1 2 3 4]\n", " println(\"i=$i\")\n", "end" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The loop iterates over elements of the array `[1 2 3 4]`. For each iteration the value of the iterator `i` is changed to the subsequent element of the iterable object." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "if you use two-dimensional arrays, the order of elements is chosen _columnwisely_." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "2×2 Matrix{Int64}:\n", " 1 2\n", " 3 4" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "A = [1 2; 3 4]" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "i=1\n", "i=3\n", "i=2\n", "i=4\n" ] } ], "source": [ "for i in A\n", " println(\"i=$i\")\n", "end" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Loops can be nested:" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "x^y=1, for x=1 and y=1.\n", "x^y=1, for x=1 and y=2.\n", "x^y=2, for x=2 and y=1.\n", "x^y=4, for x=2 and y=2.\n", "x^y=3, for x=3 and y=1.\n", "x^y=9, for x=3 and y=2.\n" ] } ], "source": [ "for x ∈ 1:3\n", " for y ∈ 1:2\n", " println(\"x^y=$(x^y), for x=$x and y=$y.\")\n", " end \n", "end" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The same thing can be written in a more compact way:" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "x^y=1, for x=1 and y=1.\n", "x^y=1, for x=1 and y=2.\n", "x^y=2, for x=2 and y=1.\n", "x^y=4, for x=2 and y=2.\n", "x^y=3, for x=3 and y=1.\n", "x^y=9, for x=3 and y=2.\n" ] } ], "source": [ "for x ∈ 1:3, y ∈ 1:2 \n", " println(\"x^y=$(x^y), for x=$x and y=$y.\") \n", "end" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The conditional mapping of elements of the vector from [our previous example](elementwise-question-example), can be solved also using a `for` loop:" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "y=[2, -4, 10, -16, 26, -36, 50, -64, 82, -100]\n" ] } ], "source": [ "x = collect(1:10)\n", "y = similar(x) #the object of the same size and type as x \n", "\n", "for i ∈ 1:length(x) \n", " y[i] = x[i]%2==0 ? -x[i]^2 : x[i]^2+1\n", "\n", "end\n", "\n", "println(\"y=$y\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Instead of using `i ∈ 1:length(x)`, we can use `(i,xᵢ) ∈ enumerate(x)`.\n", "Using this approach, the `for` loop creates one iterator equal to a counter starting at `1` and one iterator `xᵢ` equal to subsequent values of `x`:" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "y2=[2, -4, 10, -16, 26, -36, 50, -64, 82, -100]\n" ] } ], "source": [ "y2 = similar(x)\n", "for (i,xᵢ) ∈ enumerate(x)\n", " y2[i] = xᵢ%2==0 ? -xᵢ^2 : xᵢ^2+1\n", "end\n", "\n", "println(\"y2=$y2\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The most compact way to perform this operation is to use an _inline `for` loop_.\n", "This type of loops has the following structure `[operations for iterator in iterable_object ]`.\n", "\n", "\n", "In our example this will be:" ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "10-element Vector{Int64}:\n", " 2\n", " -4\n", " 10\n", " -16\n", " 26\n", " -36\n", " 50\n", " -64\n", " 82\n", " -100" ] }, "execution_count": 21, "metadata": {}, "output_type": "execute_result" } ], "source": [ "y = [ xᵢ%2==0 ? -xᵢ^2 : xᵢ^2+1 for xᵢ ∈ x ]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "I presented several ways of solving [the discussed problem](elementwise-question-example).\n", "Personally, I am the biggest fan of using a functional approach involving `map`: `map(arg -> arg%2==0 ? -arg^2 : arg^2+1 , x)`.\n", "The reason for this is that this approach is easier to be nested inside [pipes](pipes), discussed later." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "`while` loops are a traditional alternative to `for` loops.\n", "This loop is executed as long as the provided condition is true. \n", "If the condition is not met, then the execution is terminated." ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "i=0\n", "i=1\n", "i=2\n", "i=3\n", "i=4\n", "i=5\n" ] } ], "source": [ "i = 0\n", "while i ≤ 5 \n", " println(\"i=$i\")\n", " i+=1;\n", " \n", "end" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The `for` loop can imitate this behavior by combination of `break` and conditional statement. \n", "The main difference is that it has the maximum number of iterations equal to the size of the iterable object, in the case below equal to $1000.$" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "i=0\n", "i=1\n", "i=2\n", "i=3\n", "i=4\n", "i=5\n" ] } ], "source": [ "i = 0\n", "for κ ∈ 1:1000\n", " println(\"i=$i\")\n", " i+=1;\n", " if i>5 #termination condition\n", " break\n", " end \n", "end\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Command `break` terminates the current iteration of the loop and executes further code." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In this example we take negation of `i≤5`. To directly use this condition, we can use `continue` and `break`. `continue` tells `Julia` to finish the current iteration of the loop (in the current line!) and to start a new iteration.\n" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "i=0\n", "i=1\n", "i=2\n", "i=3\n", "i=4\n", "i=5\n" ] } ], "source": [ "i = 0\n", "for κ ∈ 1:1000\n", " println(\"i=$i\")\n", " i+=1;\n", " if i≤5 \n", " continue \n", " else\n", " break\n", " end \n", " \n", " 1+2+3 #this part of the loop is never executed.\n", " \n", "end\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Last and maybe the least, we can use short-circuit evaluations discussed [here](short-circuit) to make the code more compact." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "i = 0\n", "for κ ∈ 1:1000\n", " println(\"i=$i\")\n", " i+=1;\n", " \n", " i≤5 || break #termination condition. `break` is executed when `i≤5` is false\n", " \n", "end" ] } ], "metadata": { "kernelspec": { "display_name": "Julia 1.6.0", "language": "julia", "name": "julia-1.6" }, "language_info": { "file_extension": ".jl", "mimetype": "application/julia", "name": "julia", "version": "1.6.0" }, "orig_nbformat": 4 }, "nbformat": 4, "nbformat_minor": 2 }