{
 "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
}