diff --git a/0_Installation_de.ipynb b/0_Installation_de.ipynb new file mode 100644 index 0000000000000000000000000000000000000000..9ed0a9cd5a5545b74dedfa612ad3325033252dda --- /dev/null +++ b/0_Installation_de.ipynb @@ -0,0 +1,127 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "31ac33c0-18a9-4cfa-8e04-3ee1a0c909eb", + "metadata": {}, + "source": [ + "# Installation und Einrichtung\n", + "Bitte befolge die in README.md beschriebenen Schritte 1-3, um Julia herunterzuladen und zu installieren, und das Notebook 0_Installation.ipynb in einen Jupyter-notebook zu öffnen." + ] + }, + { + "cell_type": "markdown", + "id": "ff3c6951-2bc8-42b9-b2f4-acbb473300c6", + "metadata": {}, + "source": [ + "## Informationen zu Notebooks\n", + "\n", + "Notebooks sind Werkzeuge, um interaktiven Code auszuführen und die Ausgabe anzuzeigen. Sie sind sehr praktisch, um mit Code zu experimentieren und eine Programmiersprache neu zu lernen.\n", + "\n", + "Die Julia-Befehle werden in einer separaten Julia-Instanz im Hintergrund ausgeführt, der Browser ermöglicht die Interaktion mit den Notebooks (das Erstellen neuer Notebooks, das Ausführen und Modifizieren von ihnen). Beachte dass der Browser-Editor nicht mehr funktioniert wenn das Backend-Programm geschlossen wird.\n", + "\n", + "Wenn jedoch der Browser geschlossen wird, läuft das Backend weiter. Du kannst darauf zugreifen, indem Du die Adresse öffnest:\n", + "[http://localhost:8888](http://localhost:8888)" + ] + }, + { + "cell_type": "markdown", + "id": "c974b7c0-119c-4223-ad80-dce5a3ceead3", + "metadata": {}, + "source": [ + "### Notebooks\n", + "\n", + "Notebooks sind Dateien, die durch die Erweiterung `.ipynb` gekennzeichnet sind. Mit dem interaktiven Datei-Explorer kannst Du sie öffnen.\n", + "\n", + "Die Notebooks enthalten Code, die Ausgabe des Codes und können zusätzliche Kommentare enthalten (wie diese hier). Das gesamte Material des Kurses enthält noch nicht die Ausgabe des Codes, Du erhälst sie, indem Du den Code zuerst ausführst.\n", + "\n", + "Die Notebooks werden automatisch alle paar Minuten gespeichert, um jedoch sicherzustellen, dass sie gespeichert sind, kannst Du \"Strg + S\" drücken.\n" + ] + }, + { + "cell_type": "markdown", + "id": "8c98e5f5-5a92-415a-b9ec-865972d45b6f", + "metadata": {}, + "source": [ + "### Zellen\n", + "\n", + "Notebooks bestehen aus **Zellen**. Es gibt zwei Hauptarten: **Code** und **Markdown**. Dies ist eine Markdown-Zelle und wird verwendet, um Text auf eine formatierte Weise anzuzeigen.\n", + "\n", + "Die nächste ist eine Code-Zelle und wird verwendet, um Code auszuführen und dessen Ausgabe anzuzeigen. Um sie auszuführen, klicken Sie darauf und drücken Sie Shift + Enter." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8074a659-e100-49db-b83c-f0738b25cf28", + "metadata": {}, + "outputs": [], + "source": [ + "println(\"Hello World!\")" + ] + }, + { + "cell_type": "markdown", + "id": "192dac00-072c-4699-bd06-9af6ae4e3055", + "metadata": {}, + "source": [ + "Wenn Du auf eine Code-Zelle klickst, kannst Du auch deren Inhalt ändern. Um eine Markdown-Zelle zu ändern, musst Du darauf doppelklicken (dies ist jedoch für diesen Kurs nicht erforderlich).\n", + "\n", + "Es ist auch möglich, eine Code-Zelle in eine Markdown-Zelle oder umgekehrt zu ändern. Gehe dazu im oberen Menü auf Ausführen, Zellentyp.\n", + "\n", + "Schließlich können neue Zellen hinzugefügt werden, indem Du das `+`-Symbol im oberen Menü verwendest.\n", + "\n", + "Jedes Mal, wenn es eine Übung für den Leser gibt, haben wir eine leere Code-Zelle hinzugefügt." + ] + }, + { + "cell_type": "markdown", + "id": "e7730114-5064-46d1-b724-e92277ff2f90", + "metadata": {}, + "source": [ + "## Überprüfen, ob alles funktioniert\n", + "\n", + "Um zu überprüfen, ob die Installation erfolgreich war, führe die folgende Zelle aus." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7bb04662", + "metadata": {}, + "outputs": [], + "source": [ + "using Plots\n", + "\n", + "p = plot(1, xlim=(0, 3π), ylim=(-1.5, 1.5), title=\"Sine\", marker=2)\n", + "N = 100\n", + "@gif for i=1:N\n", + " x = (i-1) * 3π / N\n", + " push!(p, x, sin(x))\n", + "end" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c7d2870e", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "julia 1.9.3", + "language": "julia", + "name": "julia-1.9" + }, + "language_info": { + "file_extension": ".jl", + "mimetype": "application/julia", + "name": "julia" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/0_Installation_en.ipynb b/0_Installation_en.ipynb new file mode 100644 index 0000000000000000000000000000000000000000..7c460e566d63df5a88c224748cd0069e0b51fa85 --- /dev/null +++ b/0_Installation_en.ipynb @@ -0,0 +1,128 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "16b28ead", + "metadata": {}, + "source": [ + "# Installation and Setup\n", + "Please follow the steps 1-3 outlined in README.md to download and install Julia, and to open the notebook 0_Installation.ipynb in a Jupyter notebook. " + ] + }, + { + "cell_type": "markdown", + "id": "9161160b-87ff-4b12-bd5a-bca54228672d", + "metadata": {}, + "source": [ + "## Information about notebooks\n", + "\n", + "Notebooks are tools to interactively run code and display output. They are quite convenient for experimenting with code.\n", + "\n", + "The julia commands are run in a backend julia instance, the browser let's you interact with the notebooks (create new ones, run them, modify them). If the backend program is closed, the browser editor will stop working.\n", + "\n", + "However, if the browser is closed, the backend will keep running. You can get back to it by opening the address:\n", + "[http://localhost:8888](http://localhost:8888)" + ] + }, + { + "cell_type": "markdown", + "id": "a915cd2f-dc38-4679-8d79-c2204e2073cf", + "metadata": {}, + "source": [ + "### Notebooks\n", + "\n", + "Notebooks are files characterized by the extension `.ipynb`. Using the interactive file explorer you can open them.\n", + "\n", + "The notebooks contain code, the output of the code, and can contain additional comments (like these ones). All the material of the course does not contain yet the output of the code, you will get it by running the code first.\n", + "\n", + "The notebooks are automatically saved every now and then, however to make sure they are saved, you can press \"Ctrl + S\"." + ] + }, + { + "cell_type": "markdown", + "id": "93606623-16a4-4263-9906-a79dd3fae22f", + "metadata": {}, + "source": [ + "### Cells\n", + "\n", + "Notebooks are made up of **cells**. There are two main types: **code** and **markdown**. This is a markdown cell, it is used to display text in a formatted way.\n", + "\n", + "The next is a code cell, it is used to run code and display its output. To run it, click on it and press \"Shift + Enter\"." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8074a659-e100-49db-b83c-f0738b25cf28", + "metadata": {}, + "outputs": [], + "source": [ + "println(\"Hello World!\")" + ] + }, + { + "cell_type": "markdown", + "id": "5fc38ba1-65d0-490f-8c06-4136a7ff1372", + "metadata": {}, + "source": [ + "When you click on a code cell, you can also modify its content.\n", + "To modify a markdown cell, you need to double click on it (however this is not required by this course).\n", + "\n", + "It is also possible to transform a code cell in a markdown cell, or the other way around. To do so, go in the top menu, Run, Cell Type.\n", + "\n", + "Finally, new cells can be added by using the `+` symbol in the top menu.\n", + "\n", + "Every time there is an exercise left to the reader, we added an empty code cell." + ] + }, + { + "cell_type": "markdown", + "id": "d3d75953", + "metadata": {}, + "source": [ + "## Verifying that everything works\n", + "\n", + "To check if the installation was successfull, run the following cell." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7bb04662", + "metadata": {}, + "outputs": [], + "source": [ + "using Plots\n", + "\n", + "p = plot(1, xlim=(0, 3π), ylim=(-1.5, 1.5), title=\"Sine\", marker=2)\n", + "N = 100\n", + "@gif for i=1:N\n", + " x = (i-1) * 3π / N\n", + " push!(p, x, sin(x))\n", + "end" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c7d2870e", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "julia 1.9.3", + "language": "julia", + "name": "julia-1.9" + }, + "language_info": { + "file_extension": ".jl", + "mimetype": "application/julia", + "name": "julia" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/1_Basics_de.ipynb b/1_Basics_de.ipynb new file mode 100644 index 0000000000000000000000000000000000000000..46032fe756b3936ab958bb3a1131c714ba8bf78f --- /dev/null +++ b/1_Basics_de.ipynb @@ -0,0 +1,1258 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "aff6c2f6-3d10-412e-82aa-c199c98edbd7", + "metadata": {}, + "source": [ + "# Grundlagen" + ] + }, + { + "cell_type": "markdown", + "id": "3be02b91-9619-4cfd-b463-2add42babbcc", + "metadata": {}, + "source": [ + "## Variablen und elementare Datentypen\n", + "\n", + "Das Definieren von Variablen in Julia funktioniert wie in den meisten Sprachen:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3c44023b-06c9-4420-9af3-da2ec37b02da", + "metadata": {}, + "outputs": [], + "source": [ + "int = 4 # An integer" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b2f9ba27-bf65-40d8-b0ac-e3d86c99dd40", + "metadata": {}, + "outputs": [], + "source": [ + "str = \"Hi\" # A string" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "87a83355-5088-47d3-b698-2c6902aaa6a0", + "metadata": {}, + "outputs": [], + "source": [ + "float = 1.2 # A floating-point number" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "597523f1-4041-4fc6-9be2-2c94a93fd633", + "metadata": {}, + "outputs": [], + "source": [ + "bool = true # A boolean (also false)" + ] + }, + { + "cell_type": "markdown", + "id": "816bc593-70cc-4e0f-b461-c9022d9587f6", + "metadata": {}, + "source": [ + "Der Typ wird automatisch abgeleitet:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b80c6777-3dea-4f45-98b3-0a3eee196183", + "metadata": {}, + "outputs": [], + "source": [ + "typeof(int)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1fb6cbd2-871f-40a4-ae84-e7ee46e75a61", + "metadata": {}, + "outputs": [], + "source": [ + "typeof(str)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a16a6f08-f19a-42e0-baac-aaa88ebba1af", + "metadata": {}, + "outputs": [], + "source": [ + "typeof(float)" + ] + }, + { + "cell_type": "markdown", + "id": "d5e586cc-874a-46d5-9c7c-d1136d73492e", + "metadata": {}, + "source": [ + "Julia unterstützt von Haus aus eine große Bandbreite von Ganzzahl- und Gleitkommazahlentypen, zum Beispiel:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "88f24b01-f4a5-4030-af2c-a5d30223d047", + "metadata": {}, + "outputs": [], + "source": [ + "x = UInt8(1) # 8-bit wide unsigned integer\n", + "y = Int32(-1) # 32-bit wide signed integer\n", + "z = Float32(0.2) # single precision\n", + "α = Float16(-1.0) # half precision\n", + "β = ComplexF64(2. + 8im) # Complex number (composed of two Float64)" + ] + }, + { + "cell_type": "markdown", + "id": "bf9f6efc-6b47-415c-8504-35a2b1a80f18", + "metadata": {}, + "source": [ + "Wenn Sie einer Variable einen ungültigen Namen geben, erhalten Sie einen Syntaxfehler:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1ca20515-6d66-40c3-84f1-2e24ece096cd", + "metadata": {}, + "outputs": [], + "source": [ + "1test = \"hello\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2c61f59e-2c2f-4049-8624-35e0712b2cf1", + "metadata": {}, + "outputs": [], + "source": [ + "more@ = 1000000" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "85040b19-b0a9-4baa-8748-5ea62f8b5633", + "metadata": {}, + "outputs": [], + "source": [ + "struct = \"another illegale variable name\"" + ] + }, + { + "cell_type": "markdown", + "id": "2e5659b9-9e66-448a-a768-23d7085d7dac", + "metadata": {}, + "source": [ + "Es stellt sich heraus, dass `struct` eines der Schlüsselwörter von Julia ist und nicht als Variablennamen verwendet werden kann.\n", + "\n", + "- Für weitere Schlüsselwörter von Julia, siehe [https://docs.julialang.org/en/v1/base/base/#Keywords](https://docs.julialang.org/en/v1/base/base/#Keywords).\n", + "- Für weitere Details über `Variabeln`, siehe [https://docs.julialang.org/en/v1/manual/variables/](https://docs.julialang.org/en/v1/manual/variables/)." + ] + }, + { + "cell_type": "markdown", + "id": "e099c88a-5848-4730-be7d-b7651bc3db29", + "metadata": {}, + "source": [ + "### Zeichenketten" + ] + }, + { + "cell_type": "markdown", + "id": "925cbca6-cce3-4084-96a2-fe0a5acdb1e9", + "metadata": {}, + "source": [ + "Im Allgemeinen können Sie mathematische Operationen nicht auf Zeichenketten ausführen, auch wenn die Zeichenketten wie Zahlen aussehen. Daher sind die folgenden Operationen nicht erlaubt:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "246f1db8-d734-413d-9237-b2434e071914", + "metadata": {}, + "outputs": [], + "source": [ + "\"2\" - \"1\"\n", + "\"eggs\" / \"easy\"\n", + "\"third\" + \"a charm\"" + ] + }, + { + "cell_type": "markdown", + "id": "c2c39aa8-d98b-42dd-8e7c-09463f78d22c", + "metadata": {}, + "source": [ + "Es gibt jedoch zwei Ausnahmen, * und ^." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b3a0f6e1-e28b-4fb7-baa3-bb003de3dc24", + "metadata": {}, + "outputs": [], + "source": [ + "\"Hello \" * \"world\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0c963c3c-47c7-4805-8be6-621b72fdb62e", + "metadata": {}, + "outputs": [], + "source": [ + "\"hello! \"^5" + ] + }, + { + "cell_type": "markdown", + "id": "7b7ff4e3", + "metadata": {}, + "source": [ + "Für weitere Details: [https://docs.julialang.org/en/v1/manual/strings/](https://docs.julialang.org/en/v1/manual/strings/)." + ] + }, + { + "cell_type": "markdown", + "id": "43fe0add-b90d-4ed4-862e-37a4361d2354", + "metadata": {}, + "source": [ + "### Übungen" + ] + }, + { + "cell_type": "markdown", + "id": "3e392c67-df83-49fc-831d-12e157e4a85c", + "metadata": {}, + "source": [ + "Üben Sie, Julia als Taschenrechner zu verwenden:\n", + "\n", + " - Die Formel für das Volumen einer Kugel mit Radius r lautet 4/3πr^3. Was ist das Volumen einer Kugel mit Radius 5?" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fc538246-418c-4ebe-b487-81feba4383c8", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "id": "32f7a6f1-6a19-4ebe-bd1b-846f861dc721", + "metadata": {}, + "source": [ + "- Angenommen, der Listenpreis eines Buches beträgt € 24,95, aber Buchhandlungen erhalten einen Rabatt von 40 %. Der Versand kostet € 3 für das erste Exemplar und 75 Cent für jedes zusätzliche Exemplar. Was sind die gesamten Großhandelskosten für 60 Exemplare?\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bd4150cf-005a-4087-aa92-5f4b18e4d197", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "id": "53e26ee8-c10d-42e4-bbb9-cb5f696139ba", + "metadata": {}, + "source": [ + "## Bedingungen und boolesche Ausdrücke\n", + "\n", + "Ein boolescher Ausdruck ist ein Ausdruck, der entweder wahr oder falsch ist. Die folgenden Beispiele verwenden den Operator ==, der zwei Operanden vergleicht und true zurückgibt, wenn sie gleich sind, andernfalls false:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7de4ffe9-4730-47dd-b074-1525bf9937b1", + "metadata": {}, + "outputs": [], + "source": [ + "5 == 5" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c02939dd-6f25-4916-8394-a5f95d0200df", + "metadata": {}, + "outputs": [], + "source": [ + "5 == 6" + ] + }, + { + "cell_type": "markdown", + "id": "4722b7b7-3f80-454f-bd8b-f67912105f79", + "metadata": {}, + "source": [ + "Der == Operator ist einer der relationalen Operatoren; die anderen sind:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b59cd314-fd03-4609-ac1b-7329a2c3cc38", + "metadata": {}, + "outputs": [], + "source": [ + "x = 3; y = 4\n", + "x != y # x is not equal to y\n", + "x ≠ y # (to get the ≠ symbol, type \\ne and then press TAB)\n", + "x > y # x is greater than y\n", + "x < y # x is less than y\n", + "x >= y # x is greater than or equal to y\n", + "x ≥ y # (to get the ≥ symbol, type \\ge and then press TAB)\n", + "x <= y # x is less than or equal to y\n", + "x ≤ y # (to get the ≤ symbol, type \\le and then press TAB)" + ] + }, + { + "cell_type": "markdown", + "id": "01c9f186-294f-4659-bc32-cee3b6ff4f40", + "metadata": {}, + "source": [ + "Es gibt drei logische Operatoren: && (und), || (oder) und ! (nicht). Die Bedeutung dieser Operatoren entspricht weitgehend ihrer Bedeutung im Englischen. Zum Beispiel ist x > 0 && x < 10 nur dann wahr, wenn x größer als 0 und kleiner als 10 ist." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d1e6e2ce-bb0c-4776-80b6-22ceb9c68397", + "metadata": {}, + "outputs": [], + "source": [ + "x = 4\n", + "x > 0 && x < 10" + ] + }, + { + "cell_type": "markdown", + "id": "857cde91-3430-480c-9f24-bb9c465248d9", + "metadata": {}, + "source": [ + "Es ist auch erwähnenswert, dass bei kombinierten logischen Ausdrücken nicht alle Bedingungen notwendigerweise ausgeführt werden." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e92abf7b-5414-4aee-abaf-a4e52b1c06d3", + "metadata": {}, + "outputs": [], + "source": [ + "true || println(\"The RHS of || is only run\")\n", + "false || println(\"if the LHS is false\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c8a9d8ac-5378-4ebb-810b-9ae3194d670c", + "metadata": {}, + "outputs": [], + "source": [ + "iseven(3) && println(\"The RHS of || is only run\")\n", + "isodd(3) && println(\"if the LHS is true\")" + ] + }, + { + "cell_type": "markdown", + "id": "d8db49a8-6c6c-4abf-9a5b-5d27765ab1c7", + "metadata": {}, + "source": [ + "Schließlich kehrt der ! Operator einen booleschen Ausdruck um, sodass !(x > y) wahr ist, wenn x > y falsch ist, das heißt, wenn x kleiner oder gleich y ist." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e43ab736-03e2-4040-a15e-48305037ba23", + "metadata": {}, + "outputs": [], + "source": [ + "x = 4\n", + "!(x > 0 && x < 10)" + ] + }, + { + "cell_type": "markdown", + "id": "fbe0d04d-29c9-4bd0-9cfb-0c57a3b3f877", + "metadata": {}, + "source": [ + "Es überrascht nicht, dass Julia die üblichen Bedingungsanweisungen hat." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4f140e2c-a240-496d-904c-c60778397bcf", + "metadata": {}, + "outputs": [], + "source": [ + "x = 3; y = 2\n", + "\n", + "if x < y\n", + " println(\"x is less than y\")\n", + "elseif x > y\n", + " println(\"x is greater than y\")\n", + "else\n", + " println(\"x is equal to y\")\n", + "end" + ] + }, + { + "cell_type": "markdown", + "id": "64a3bf26-156f-40a8-8d8c-d4b2f838ef95", + "metadata": {}, + "source": [ + "Es gibt auch eine bedingte Inline-Anweisung." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9d0801fd-b0d3-41e0-8b54-19a6b4539231", + "metadata": {}, + "outputs": [], + "source": [ + "x = 6\n", + "x < 5 ? \"smaller than 5\" : \"larger or equal 5\"" + ] + }, + { + "cell_type": "markdown", + "id": "2539a6ec-e950-4b76-ad13-4ac9bb28ec26", + "metadata": {}, + "source": [ + "Für weitere Details siehe: [https://docs.julialang.org/en/v1/manual/control-flow/](https://docs.julialang.org/en/v1/manual/control-flow/)" + ] + }, + { + "cell_type": "markdown", + "id": "7c8eb301-3404-4d13-bc5d-f4e2f71cfa12", + "metadata": {}, + "source": [ + "## Iterationen\n", + "\n", + "Julia implementiert die üblichen `for`- und `while`-Befehle." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9632f210-c713-4829-8187-cf5554adad87", + "metadata": {}, + "outputs": [], + "source": [ + "for i in 1:5\n", + " println(\"Hello from number $i\")\n", + "end" + ] + }, + { + "cell_type": "markdown", + "id": "d0933cf7-b409-4c40-8184-70d0770a06b1", + "metadata": {}, + "source": [ + "Dabei ist `1:5` ein `Range`-Objekt, aber es könnte jede Art von iterierbarem Objekt sein. Es gibt einige syntaktische Variationen, einschließlich:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "70a9f620-e4ce-4367-b0f5-de37db3f48b5", + "metadata": {}, + "outputs": [], + "source": [ + "result = 0\n", + "# To get ∈ write \\in and then press TAB\n", + "for j ∈ 1:0.5:3 # Note the step parameter\n", + " result += j\n", + "end\n", + "println(result)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e83b2d88-b0f2-43f1-9187-65fbc75f0d3b", + "metadata": {}, + "outputs": [], + "source": [ + "n = 10\n", + "while n > 0\n", + " print(n, \" \")\n", + " n = n - 1\n", + "end" + ] + }, + { + "cell_type": "markdown", + "id": "76563c39-4e45-4daf-b703-575909f70787", + "metadata": {}, + "source": [ + "Die Schleifen können mit den Schlüsselwörtern `break` und `continue` weiter gesteuert werden." + ] + }, + { + "cell_type": "markdown", + "id": "b38f525d-db83-4fbf-808c-bf39080650f5", + "metadata": {}, + "source": [ + "Manchmal weiß man nicht, wann es an der Zeit ist, eine Schleife zu beenden, bis man sich bereits in der Mitte des Schleifenkörpers befindet. In diesem Fall können Sie das `break`-Statement verwenden, um aus der Schleife auszubrechen." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9bb642e3-e3b1-488d-939f-6932feb62479", + "metadata": {}, + "outputs": [], + "source": [ + "while true\n", + " print(\"> \")\n", + " line = readline()\n", + " if line == \"done\"\n", + " break\n", + " end\n", + " println(line)\n", + "end\n", + "println(\"Done!\")" + ] + }, + { + "cell_type": "markdown", + "id": "873c3625-3b99-48e5-9821-9b696a8f8a12", + "metadata": {}, + "source": [ + "Das `break`-Statement beendet die Schleife. Wenn ein `continue`-Statement in einer Schleife auftritt, springt die Kontrolle zum Anfang der Schleife für die nächste Iteration, wobei die Ausführung der Anweisungen im Innern der Schleife für die aktuelle Iteration übersprungen wird. Zum Beispiel:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7f1c2595-8836-4308-9769-f4140d402582", + "metadata": {}, + "outputs": [], + "source": [ + "for i in 1:10\n", + " if i % 3 == 0\n", + " continue\n", + " end\n", + " print(i, \" \")\n", + "end" + ] + }, + { + "cell_type": "markdown", + "id": "d2e93721", + "metadata": {}, + "source": [ + "Für weitere Details: [https://docs.julialang.org/en/v1/base/collections/#lib-collections-iteration](https://docs.julialang.org/en/v1/base/collections/#lib-collections-iteration)." + ] + }, + { + "cell_type": "markdown", + "id": "625f1e1b-ab4d-425d-b848-94385ddcb690", + "metadata": {}, + "source": [ + "### Übungen" + ] + }, + { + "cell_type": "markdown", + "id": "6a0dcd06-0926-4529-ac33-0aee315f85cf", + "metadata": {}, + "source": [ + "Der Mathematiker Srinivasa Ramanujan fand eine unendliche Reihe, die verwendet werden kann, um eine numerische Näherung von 1/π zu generieren:\n", + "\n", + "$$ \\frac{1}{\\pi} = \\frac{2\\sqrt{2}}{9801} \\sum_{k=0}^\\infty \\frac{(4k)! (1103 + 26390 k)}{(k!)^4 396^{4 k}}$$\n", + "\n", + "Verwenden Sie diese Formel, um eine Schätzung von π zu berechnen. Sie sollte eine While-Schleife verwenden, um die Terme der Summation zu berechnen, bis der letzte Term kleiner als 1e-15 ist. Anschließend können Sie das Ergebnis überprüfen, indem Sie es mit π vergleichen (um π in Julia zu erhalten, schreiben Sie \\pi und drücken dann die TAB-Taste). Hinweis: Verwenden Sie die integrierte Funktion `factorial`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "dbe40300-8333-4271-aa43-49f973fa03a6", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "id": "e2072b09-53e0-4354-984b-13813e93fef1", + "metadata": {}, + "source": [ + "## Funktionen" + ] + }, + { + "cell_type": "markdown", + "id": "8fde350c-f73a-44b7-9459-b8f6d79120cf", + "metadata": {}, + "source": [ + "Wir haben bereits ein Beispiel für einen Funktionsaufruf gesehen:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "addaa346-7a88-4c18-9f1e-295665959a9d", + "metadata": {}, + "outputs": [], + "source": [ + "println(\"Hello, World!\")" + ] + }, + { + "cell_type": "markdown", + "id": "ef1e8206-add5-49f9-ab4c-4b730164aee6", + "metadata": {}, + "source": [ + "Der Name der Funktion ist println. Der Ausdruck in Klammern wird als Argument der Funktion bezeichnet.\n", + "Es ist üblich zu sagen, dass eine Funktion ein Argument \"nimmt\" und ein Ergebnis \"zurückgibt\". Das Ergebnis wird auch als Rückgabewert bezeichnet.\n" + ] + }, + { + "cell_type": "markdown", + "id": "bd083417-b51a-4f0e-a150-56a0f9c33569", + "metadata": {}, + "source": [ + "Julia bietet Funktionen, die Werte von einem Typ in einen anderen konvertieren. Die Funktion `parse` nimmt einen String und wandelt ihn in jeden Zahlen-Typ um, wenn es möglich ist, oder gibt andernfalls eine Fehlermeldung aus:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1f05465a-4863-4205-9c73-26f0e93f049b", + "metadata": {}, + "outputs": [], + "source": [ + "parse(Int64, \"32\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e6ac9994-9cbb-4004-889d-a657b8396063", + "metadata": {}, + "outputs": [], + "source": [ + "parse(Int64, \"Hello\")" + ] + }, + { + "cell_type": "markdown", + "id": "9176592b-e9f3-46fd-9909-8b73da750434", + "metadata": {}, + "source": [ + "Julia stellt verschiedene mathematische Funktionen zur Verfügung:\n", + " - abs, sqrt, cbrt, exp, log, log10, log2\n", + " - sin, cos, tan, asin, acos, atan\n", + " - sinh, cosh, tanh, asinh, acosh, atanh\n", + " - floor: Größte ganze Zahl, die nicht größer als x ist.\n", + " - ceil: Kleinste ganze Zahl, die nicht kleiner als x ist.\n", + " - round: Nächstgelegene ganze Zahl zu x.\n", + " - trunc: Ganzzahliger Teil von x.\n", + "\n", + "Für weitere Details: [https://docs.julialang.org/en/v1/base/math/#Mathematical-Functions](https://docs.julialang.org/en/v1/base/math/#Mathematical-Functions)." + ] + }, + { + "cell_type": "markdown", + "id": "f43cb468-832a-4cab-b8a3-15bb9bcbfb0d", + "metadata": {}, + "source": [ + "Bisher haben wir nur die Funktionen verwendet, die mit Julia geliefert werden, aber es ist auch möglich, neue Funktionen hinzuzufügen.\n", + "Die Definition von Funktionen folgt einer recht intuitiven Syntax. Der Wert, der durch Auswerten des letzten Ausdrucks eines `function`-Blocks erhalten wird, wird automatisch zurückgegeben:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fd2f4828-47f5-4df4-b5bd-a42625487b5a", + "metadata": {}, + "outputs": [], + "source": [ + "function mymult(x, y)\n", + " x * y\n", + "end" + ] + }, + { + "cell_type": "markdown", + "id": "e8dfb238-54be-4a95-9eda-4ce1fa5cfd74", + "metadata": {}, + "source": [ + "Für Einzeiler-Funktionen kann man auch eine praktische Kurzschreibweise verwenden:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5ed8292a-96e2-49ad-8f00-3c07b9483637", + "metadata": {}, + "outputs": [], + "source": [ + "mysquare(x) = mymult(x, x)" + ] + }, + { + "cell_type": "markdown", + "id": "9b688bbf-08b6-4fba-babe-b16b6e1119be", + "metadata": {}, + "source": [ + "Beide Funktionen sind in den Argumenttypen vollständig generisch" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "49ceeeff-5291-460d-800d-5ed11a03b13e", + "metadata": {}, + "outputs": [], + "source": [ + "@show mysquare(2) # Use integer arithmetic\n", + "@show mymult(-1, 3. + 2im) # Use complex arithmetic\n", + "@show mysquare(\" abc \"); # Use string concatenation" + ] + }, + { + "cell_type": "markdown", + "id": "6add8ab6-7f66-431b-9e9e-e52d45379483", + "metadata": {}, + "source": [ + "Beachten Sie, dass für jede Kombination von Typen ein separater Codeabschnitt kompiliert wird, obwohl wir die Funktionalität nur einmal *definiert* haben. Diese Kompilierung findet beim ersten Gebrauch eines bestimmten Tupels von Typen statt." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7e5dcfeb-960a-47f3-b2f8-f6f0906d2f24", + "metadata": {}, + "outputs": [], + "source": [ + "mymult" + ] + }, + { + "cell_type": "markdown", + "id": "3be89ab5-16f3-4633-bb8d-fd74cf39ddec", + "metadata": {}, + "source": [ + "und können an andere Funktionen übergeben werden, zum Beispiel:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "171b1a83-c076-4ac4-a309-9d607ea0b5a4", + "metadata": {}, + "outputs": [], + "source": [ + "\"\"\"The fold function, applying f from the left and accumulating the results\"\"\"\n", + "function myfold(f, x, y, z)\n", + " f(f(x, y), z)\n", + "end\n", + "myfold(mymult, \"Hello\", \" Julia \", \"World\")" + ] + }, + { + "cell_type": "markdown", + "id": "09a40182-e59f-42e4-b11e-0c3aedd0e7a6", + "metadata": {}, + "source": [ + "Julia unterscheidet zwischen **Funktionen** und **Methoden**. Grob gesagt geben **Funktionen** an, *was* gemacht wird, und **Methoden** geben an, *wie* dies gemacht wird.\n", + "\n", + "Methoden sind konkrete Implementierungen in Form von einer Liste von Julia-Ausdrücken, die ausgeführt werden, wenn der Funktionsname im Code verwendet wird. Für den gleichen Funktionsnamen können mehrere Methoden definiert werden. Sie unterscheiden sich in der Anzahl der Argumente oder in den unterstützten Argumenttypen (dazu mehr im nächsten Notebook). Wenn ein bestimmter Funktionsname im Code verwendet wird, betrachtet Julia die Typen der Argumente und verwendet diese Informationen, um zur am besten passenden Methode zu **dispatchen**.\n", + "\n", + "Für unser `myfold`-Beispiel könnte man sich leicht einige weitere Methodenimplementierungen vorstellen, zum Beispiel:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c249f818-6544-42fe-b387-34058e5f5890", + "metadata": {}, + "outputs": [], + "source": [ + "myfold(f, x) = x\n", + "myfold(f, x, y) = f(x, y)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "88f62159-2a1b-4a5a-8434-0e91810f2c69", + "metadata": {}, + "outputs": [], + "source": [ + "methods(myfold)" + ] + }, + { + "cell_type": "markdown", + "id": "cc818df4-a037-4ba2-8588-1afe4a6de222", + "metadata": {}, + "source": [ + "Nun funktioniert `myfold` transparent mit 1, 2 oder 3 Argumenten:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d67f9c21-2c5c-43fd-a7e4-a4ce74281bf0", + "metadata": {}, + "outputs": [], + "source": [ + "@show myfold(mymult, 2., 3.)\n", + "@show myfold(+, 1)\n", + "@show myfold(==, false, false, true)" + ] + }, + { + "cell_type": "markdown", + "id": "5a9a652b-80c4-482f-80b8-2c5340e61a21", + "metadata": {}, + "source": [ + "Wir können auch überprüfen, welche Methode tatsächlich verwendet wird, indem wir das `@which`-Makro verwenden:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0fa105fb-b3ad-405a-85f1-598a12cbc655", + "metadata": {}, + "outputs": [], + "source": [ + "@which myfold(*, 1, 2)" + ] + }, + { + "cell_type": "markdown", + "id": "4046d2e8-2018-4f4f-b816-2a6156301f39", + "metadata": {}, + "source": [ + "Standardfunktionen (wie `+` oder `*`) sind keineswegs speziell und verhalten sich genau wie benutzerdefinierte Funktionen ... einschließlich der Möglichkeit, neue Methoden für sie zu definieren:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d771af33-5174-4a95-b8e3-ac1c29eb71e9", + "metadata": {}, + "outputs": [], + "source": [ + "import Base: + # we have to import functions to override/extend them\n", + "+(x::String, y::String) = x * \" \" * y" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "32429003-4879-4a37-ad3c-153857a360dd", + "metadata": {}, + "outputs": [], + "source": [ + "\"Hello\" + \"World!\"" + ] + }, + { + "cell_type": "markdown", + "id": "ee25eff6-f56e-4230-b52d-6020dcc29bb2", + "metadata": {}, + "source": [ + "(**Wichtiger Hinweis:** Da wir weder die `+` Funktion noch den `String` Typ besitzen, handelt es sich hierbei um **Typenpiraterie** und sollte im Allgemeinen vermieden werden!)" + ] + }, + { + "cell_type": "markdown", + "id": "a2c9d8cf-0462-415c-a466-edb33b3aadec", + "metadata": {}, + "source": [ + "Nun funktionieren Standardfunktionen, die auf `+` angewiesen sind, einfach magisch:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "75b4afeb-a3f4-40d7-8b23-b961b01c41bc", + "metadata": {}, + "outputs": [], + "source": [ + "sum([\"a\", \"b\", \"c\", \"d\", \"e\"])" + ] + }, + { + "cell_type": "markdown", + "id": "013b3faf-5f12-482b-956e-de97a2a4830d", + "metadata": {}, + "source": [ + "Variablen und Parameter sind lokal, sie existieren nur innerhalb der Funktionen, in denen sie definiert sind:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d02e6bca-6723-4a05-82ee-1f30ba127bd5", + "metadata": {}, + "outputs": [], + "source": [ + "function multiply_and_print(a, b)\n", + " product = a * b\n", + " println(product)\n", + "end\n", + "\n", + "multiply_and_print(2, 3)\n", + "println(product)" + ] + }, + { + "cell_type": "markdown", + "id": "0a398295-22e0-45dc-b43c-5f1915a16364", + "metadata": {}, + "source": [ + "Es mag nicht klar sein, warum es sich lohnt, ein Programm in Funktionen zu unterteilen. Es gibt mehrere Gründe dafür:\n", + "\n", + "- Das Erstellen einer neuen Funktion bietet die Möglichkeit, eine Gruppe von Anweisungen zu benennen, was das Programm leichter lesbar und einfacher zu debuggen macht.\n", + "- Funktionen können ein Programm kleiner machen, indem sie wiederholten Code eliminieren. Später, wenn Sie eine Änderung vornehmen, müssen Sie sie nur an einer Stelle vornehmen.\n", + "- Das Aufteilen eines langen Programms in Funktionen ermöglicht es Ihnen, die Teile nacheinander zu debuggen und dann zu einem funktionierenden Ganzen zusammenzufügen.\n", + "- Gut gestaltete Funktionen sind oft für viele Programme nützlich. Sobald Sie eine geschrieben und debuggt haben, können Sie sie wiederverwenden.\n", + "- In Julia können Funktionen die Schnelligkeit erheblich verbessern.\n" + ] + }, + { + "cell_type": "markdown", + "id": "dfa722c2-bd4c-4162-b10d-24c0f8e990e0", + "metadata": {}, + "source": [ + "Weitere Details finden Sie unter: [https://docs.julialang.org/en/v1/manual/methods/](https://docs.julialang.org/en/v1/manual/methods/)" + ] + }, + { + "cell_type": "markdown", + "id": "a4eafce6-b493-470f-86a3-93319684ee40", + "metadata": {}, + "source": [ + "### Übungen" + ] + }, + { + "cell_type": "markdown", + "id": "08fe364b-e611-419b-97f2-e806881d6227", + "metadata": {}, + "source": [ + "- Schreiben Sie eine Funktion `printgrid`, die ein Raster wie folgt zeichnet:" + ] + }, + { + "cell_type": "markdown", + "id": "1704f451-9500-41c5-b74b-4a2b4a7b910f", + "metadata": {}, + "source": [ + " + - - - - + - - - - +\n", + " | | |\n", + " | | |\n", + " | | |\n", + " | | |\n", + " + - - - - + - - - - +\n", + " | | |\n", + " | | |\n", + " | | |\n", + " | | |\n", + " + - - - - + - - - - +" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "58ef3248-f85e-4825-bf10-02cee3e068cb", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "id": "41f2bf0f-73f4-4671-b059-1118c35ec76f", + "metadata": {}, + "source": [ + "- Schreiben Sie eine Funktion, die ein ähnliches Raster mit vier Zeilen und vier Spalten zeichnet." + ] + }, + { + "cell_type": "markdown", + "id": "2e606498-6553-4037-a9f9-3b519ffc64c9", + "metadata": {}, + "source": [ + "Tipps:\n", + "- Um mehr als einen Wert in einer Zeile auszugeben, können Sie eine kommagetrennte Sequenz von Werten ausgeben: println(\"+\", \"-\").\n", + "- Die Funktion print springt nicht zur nächsten Zeile." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1ca1789d-eddb-4f41-9ad9-9259c6f22a14", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "id": "53edcb8b-2f37-404f-8df6-d84b2327e96e", + "metadata": {}, + "source": [ + "### Rekursive Funktionen\n", + "\n", + "Es ist erlaubt, dass eine Funktion eine andere aufruft; es ist auch erlaubt, dass eine Funktion sich selbst aufruft. Es mag nicht offensichtlich sein, warum das eine gute Sache ist, aber es stellt sich heraus, dass es eine der magischsten Dinge ist, die ein Programm tun kann. Schauen Sie sich zum Beispiel die folgende Funktion an:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e578011e-d0de-4f86-8c2c-a8408454d3ac", + "metadata": {}, + "outputs": [], + "source": [ + "function countdown(n)\n", + " if n ≤ 0\n", + " println(\"Blastoff!\")\n", + " else\n", + " print(n, \" \")\n", + " countdown(n-1)\n", + " end\n", + "end" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3af51513-c92e-4488-b2fe-243e2fef6b95", + "metadata": {}, + "outputs": [], + "source": [ + "countdown(10)" + ] + }, + { + "cell_type": "markdown", + "id": "73ea203a-3919-4e14-b50f-22c8362eb771", + "metadata": {}, + "source": [ + "Wenn eine Rekursion niemals einen Basisfall erreicht, macht sie unendliche rekursive Aufrufe, und das Programm terminiert nie. Dies wird als unendliche Rekursion bezeichnet und ist im Allgemeinen keine gute Idee. Hier ist ein minimales Programm mit einer unendlichen Rekursion:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "13a4a762-6584-47ab-9fb5-428557770d15", + "metadata": {}, + "outputs": [], + "source": [ + "function recurse()\n", + " recurse()\n", + "end" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0dde579f-6b12-4072-aa62-aeee3a970503", + "metadata": {}, + "outputs": [], + "source": [ + "recurse()" + ] + }, + { + "cell_type": "markdown", + "id": "a0402c3d-95fa-44a1-86ab-ca229508f68f", + "metadata": {}, + "source": [ + "### Übungen\n", + " - Schreiben Sie eine rekursive Funktion zur Berechnung der Fakultät einer Zahl." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f4102487-011e-474f-ab79-3d7db1d3bbd9", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "id": "a24cdaef-98b8-46f5-a809-992547882a4b", + "metadata": {}, + "source": [ + " - Schreiben Sie dann eine Funktion, die die Binomialkoeffizienten berechnet\n", + "$$ \\left(\\begin{array}{c} n \\\\ k \\end{array}\\right) = \\frac{n!}{k! (n-k)!} $$\n", + "indem sie die Funktion aus den vorherigen Punkten aufruft." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b54c877e-5494-4657-ba7f-208bdc301225", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "id": "a32900cc-c244-4d63-8ff6-4d11cee83eee", + "metadata": {}, + "source": [ + " - Verwenden Sie die beiden Funktionen, um folgendes zu berechnen\n", + "$$ 15! \\qquad \\left(\\begin{array}{c} 5 \\\\ 2 \\end{array}\\right) \\qquad \\left(\\begin{array}{c} 5 \\\\ 3 \\end{array}\\right) $$" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fb02aad5-d9d4-4f0d-8118-b02b73506b89", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "id": "b5944412-0d39-4c0b-a0d5-fbeee22e1432", + "metadata": {}, + "source": [ + "### Schlüsselwortargumente\n", + "\n", + "Funktionsargumente können entweder positionsbasiert (wie wir bisher gesehen haben) oder schlüsselwortbasiert sein, wie im folgenden Beispiel." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "30ddeb3b-be35-40eb-8491-1269a4e19f62", + "metadata": {}, + "outputs": [], + "source": [ + "function greet(name; greeting=\"Hello\")\n", + " println(\"$(greeting), $(name)!\")\n", + "end" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b39f22b1-4a1b-4afd-b6db-041bd7150b66", + "metadata": {}, + "outputs": [], + "source": [ + "greet(\"Michele\")\n", + "greet(\"Lambert\"; greeting=\"Hallo\")\n", + "greet(\"YingXing\"; greeting=\"你好\")" + ] + }, + { + "cell_type": "markdown", + "id": "07e76016-d5a9-4616-b0b9-2dc9b6f3c8f6", + "metadata": {}, + "source": [ + "Dies ist in den folgenden Fällen sehr praktisch:\n", + " - um ein Standardverhalten der Funktion festzulegen, während die Möglichkeit besteht, sie fein zu steuern.\n", + " - um zu einem späteren Zeitpunkt neue Funktionalitäten hinzuzufügen, ohne die Abwärtskompatibilität zu brechen." + ] + }, + { + "cell_type": "markdown", + "id": "883b3945-d30a-4f27-928f-458c9ad74e9b", + "metadata": {}, + "source": [ + "## Weitere Übungen" + ] + }, + { + "cell_type": "markdown", + "id": "54537041-60eb-4961-9805-1d7d405fde1a", + "metadata": {}, + "source": [ + "- Erstellen Sie eine Funktion namens `fibonacci_sum`, die eine positive ganze Zahl n als Eingabe erhält. Diese Funktion sollte die Summe der ersten n Terme der Fibonacci-Folge zurückgeben." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7ca7c936-fb80-4aed-9788-75a55bb207ad", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "id": "70dacb25-360f-4a7a-8c03-73cd0d75dc3e", + "metadata": {}, + "source": [ + "- Schreiben Sie eine Funktion, die eine Celsius-Temperatur in Fahrenheit umrechnet und das Ergebnis zurückgibt. Zusätzlich sollte das Programm, wenn die Temperatur unter dem Gefrierpunkt (0°C) liegt, eine Meldung ausgeben, die anzeigt, dass es unter dem Gefrierpunkt liegt." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a30a1812-6116-4441-8786-7450c60ef354", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "id": "8cabe824-c7eb-46fc-afb8-e039528d2d2a", + "metadata": {}, + "source": [ + "- Schreiben Sie eine Funktion, die einen Satz analysiert. Die Funktion sollte dann die Anzahl der Vokale (sowohl in Groß- als auch in Kleinbuchstaben) im Satz zählen und anzeigen." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "af0e28bd-2b3f-41af-aa92-456e29d50679", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Julia 1.9.3", + "language": "julia", + "name": "julia-1.9" + }, + "language_info": { + "file_extension": ".jl", + "mimetype": "application/julia", + "name": "julia" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/1_Basics_en.ipynb b/1_Basics_en.ipynb new file mode 100644 index 0000000000000000000000000000000000000000..d7838a5cebe9a921aeec8e4d056d58d8e7905ace --- /dev/null +++ b/1_Basics_en.ipynb @@ -0,0 +1,1256 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "7aad3586-d57e-4000-8688-aa5b53d48416", + "metadata": {}, + "source": [ + "# Basics" + ] + }, + { + "cell_type": "markdown", + "id": "bf904dbe-3197-4a91-bbb8-05e1c7f7dfee", + "metadata": {}, + "source": [ + "## Variables and elementary types\n", + "\n", + "Defining variables in Julia works like in most languages:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3c44023b-06c9-4420-9af3-da2ec37b02da", + "metadata": {}, + "outputs": [], + "source": [ + "int = 4 # An integer" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b2f9ba27-bf65-40d8-b0ac-e3d86c99dd40", + "metadata": {}, + "outputs": [], + "source": [ + "str = \"Hi\" # A string" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "87a83355-5088-47d3-b698-2c6902aaa6a0", + "metadata": {}, + "outputs": [], + "source": [ + "float = 1.2 # A floating-point number" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "597523f1-4041-4fc6-9be2-2c94a93fd633", + "metadata": {}, + "outputs": [], + "source": [ + "bool = true # A boolean (also false)" + ] + }, + { + "cell_type": "markdown", + "id": "0c538bdb-f995-4589-bee7-0989c922090c", + "metadata": {}, + "source": [ + "The type is automatically inferred:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b80c6777-3dea-4f45-98b3-0a3eee196183", + "metadata": {}, + "outputs": [], + "source": [ + "typeof(int)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1fb6cbd2-871f-40a4-ae84-e7ee46e75a61", + "metadata": {}, + "outputs": [], + "source": [ + "typeof(str)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a16a6f08-f19a-42e0-baac-aaa88ebba1af", + "metadata": {}, + "outputs": [], + "source": [ + "typeof(float)" + ] + }, + { + "cell_type": "markdown", + "id": "09d035eb-22aa-49f5-9fd1-a5b16973f386", + "metadata": {}, + "source": [ + "Julia supports a large range of integer and floating-point types out of the box, for example:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "88f24b01-f4a5-4030-af2c-a5d30223d047", + "metadata": {}, + "outputs": [], + "source": [ + "x = UInt8(1) # 8-bit wide unsigned integer\n", + "y = Int32(-1) # 32-bit wide signed integer\n", + "z = Float32(0.2) # single precision\n", + "α = Float16(-1.0) # half precision\n", + "β = ComplexF64(2. + 8im) # Complex number (composed of two Float64)" + ] + }, + { + "cell_type": "markdown", + "id": "a615bbc0-732e-461f-8c4c-a972fa2be731", + "metadata": {}, + "source": [ + "If you give a variable an illegal name, you get a syntax error:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1ca20515-6d66-40c3-84f1-2e24ece096cd", + "metadata": {}, + "outputs": [], + "source": [ + "1test = \"hello\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2c61f59e-2c2f-4049-8624-35e0712b2cf1", + "metadata": {}, + "outputs": [], + "source": [ + "more@ = 1000000" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "85040b19-b0a9-4baa-8748-5ea62f8b5633", + "metadata": {}, + "outputs": [], + "source": [ + "struct = \"another illegale variable name\"" + ] + }, + { + "cell_type": "markdown", + "id": "cc36688b-c983-43f8-8bdf-9b82aae59909", + "metadata": {}, + "source": [ + "It turns out that `struct` is one of Julia’s keywords, and they cannot be used as variable names. \n", + "\n", + "- For more Julia's keywords, see [https://docs.julialang.org/en/v1/base/base/#Keywords](https://docs.julialang.org/en/v1/base/base/#Keywords). \n", + "- For more details on `Variable`, see [https://docs.julialang.org/en/v1/manual/variables/](https://docs.julialang.org/en/v1/manual/variables/)." + ] + }, + { + "cell_type": "markdown", + "id": "de111dbe-f7ed-4e1a-8ec0-c5e65bd63bbf", + "metadata": {}, + "source": [ + "### Strings" + ] + }, + { + "cell_type": "markdown", + "id": "1b3531e9-33db-4c51-b394-c1def6621519", + "metadata": {}, + "source": [ + "In general, you can’t perform mathematical operations on strings, even if the strings look like numbers, so the following are illegal:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "246f1db8-d734-413d-9237-b2434e071914", + "metadata": {}, + "outputs": [], + "source": [ + "\"2\" - \"1\"\n", + "\"eggs\" / \"easy\"\n", + "\"third\" + \"a charm\"" + ] + }, + { + "cell_type": "markdown", + "id": "c94f1187-67f8-473e-910c-2eb145ed59dd", + "metadata": {}, + "source": [ + "But there are two exceptions, * and ^." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b3a0f6e1-e28b-4fb7-baa3-bb003de3dc24", + "metadata": {}, + "outputs": [], + "source": [ + "\"Hello \" * \"world\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0c963c3c-47c7-4805-8be6-621b72fdb62e", + "metadata": {}, + "outputs": [], + "source": [ + "\"hello! \"^5" + ] + }, + { + "cell_type": "markdown", + "id": "362f9d04-eff9-4594-aa22-a9c8d601fb1e", + "metadata": {}, + "source": [ + "For more details: [https://docs.julialang.org/en/v1/manual/strings/](https://docs.julialang.org/en/v1/manual/strings/)." + ] + }, + { + "cell_type": "markdown", + "id": "61ff8194-669c-4ece-ba31-44e88ed808ac", + "metadata": {}, + "source": [ + "### Exercises" + ] + }, + { + "cell_type": "markdown", + "id": "e0aecc9c-e77f-449e-8aff-e1ffcf5d7833", + "metadata": {}, + "source": [ + "Practice using Julia as a calculator:\n", + " - The volume of a sphere with radius r is 4/3πr^3. What is the volume of a sphere with radius 5?" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fc538246-418c-4ebe-b487-81feba4383c8", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "id": "10f1604d-8e81-4f96-8b6f-95753f0b5c4f", + "metadata": {}, + "source": [ + " - Suppose the cover price of a book is € 24.95, but bookstores get a 40 % discount. Shipping costs € 3 for the first copy and 75 cents for each additional copy. What is the total wholesale cost for 60 copies?" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bd4150cf-005a-4087-aa92-5f4b18e4d197", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "id": "dc9cddb9-717d-4ba0-b478-beb00afc46c8", + "metadata": {}, + "source": [ + "## Conditionals and Boolean Expressions\n", + "\n", + "A boolean expression is an expression that is either true or false. The following examples use the operator ==, which compares two operands and produces true if they are equal and false otherwise:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7de4ffe9-4730-47dd-b074-1525bf9937b1", + "metadata": {}, + "outputs": [], + "source": [ + "5 == 5" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c02939dd-6f25-4916-8394-a5f95d0200df", + "metadata": {}, + "outputs": [], + "source": [ + "5 == 6" + ] + }, + { + "cell_type": "markdown", + "id": "9a108e63-7d58-489d-b7ef-49629c879d29", + "metadata": {}, + "source": [ + "The == operator is one of the relational operators; the others are:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b59cd314-fd03-4609-ac1b-7329a2c3cc38", + "metadata": {}, + "outputs": [], + "source": [ + "x = 3; y = 4\n", + "x != y # x is not equal to y\n", + "x ≠ y # (to get the ≠ symbol, type \\ne and then press TAB)\n", + "x > y # x is greater than y\n", + "x < y # x is less than y\n", + "x >= y # x is greater than or equal to y\n", + "x ≥ y # (to get the ≥ symbol, type \\ge and then press TAB)\n", + "x <= y # x is less than or equal to y\n", + "x ≤ y # (to get the ≤ symbol, type \\le and then press TAB)" + ] + }, + { + "cell_type": "markdown", + "id": "15e20f55-1a43-4d0d-94bc-d2de0ee2fe8c", + "metadata": {}, + "source": [ + "There are three logical operators: && (and), || (or), and ! (not). The semantics (meaning) of these operators is similar to their meaning in English. For example, x > 0 && x < 10 is true only if x is greater than 0 and less than 10. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d1e6e2ce-bb0c-4776-80b6-22ceb9c68397", + "metadata": {}, + "outputs": [], + "source": [ + "x = 4\n", + "x > 0 && x < 10" + ] + }, + { + "cell_type": "markdown", + "id": "da591654-6360-4f56-956b-07493d1d2247", + "metadata": {}, + "source": [ + "It is also worth mentioning that in combined logical expression not all conditions are necessarily executed." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e92abf7b-5414-4aee-abaf-a4e52b1c06d3", + "metadata": {}, + "outputs": [], + "source": [ + "true || println(\"The RHS of || is only run\")\n", + "false || println(\"if the LHS is false\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c8a9d8ac-5378-4ebb-810b-9ae3194d670c", + "metadata": {}, + "outputs": [], + "source": [ + "iseven(3) && println(\"The RHS of || is only run\")\n", + "isodd(3) && println(\"if the LHS is true\")" + ] + }, + { + "cell_type": "markdown", + "id": "be0c63e0-35a9-43c7-9b30-d04072ee6904", + "metadata": {}, + "source": [ + "Finally, the ! operator negates a boolean expression, so !(x > y) is true if x > y is false, that is, if x is less than or equal to y." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e43ab736-03e2-4040-a15e-48305037ba23", + "metadata": {}, + "outputs": [], + "source": [ + "x = 4\n", + "!(x > 0 && x < 10)" + ] + }, + { + "cell_type": "markdown", + "id": "7064ae20-6d63-40fc-85c5-080ace54e7b6", + "metadata": {}, + "source": [ + "Unsurprisingly Julia has the standard conditionals." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4f140e2c-a240-496d-904c-c60778397bcf", + "metadata": {}, + "outputs": [], + "source": [ + "x = 3; y = 2\n", + "\n", + "if x < y\n", + " println(\"x is less than y\")\n", + "elseif x > y\n", + " println(\"x is greater than y\")\n", + "else\n", + " println(\"x is equal to y\")\n", + "end" + ] + }, + { + "cell_type": "markdown", + "id": "4c57139e-da0c-48ef-a86f-4de80e1d7ca4", + "metadata": {}, + "source": [ + "There is also an inline conditional." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9d0801fd-b0d3-41e0-8b54-19a6b4539231", + "metadata": {}, + "outputs": [], + "source": [ + "x = 6\n", + "x < 5 ? \"smaller than 5\" : \"larger or equal 5\"" + ] + }, + { + "cell_type": "markdown", + "id": "b597c363-8066-470e-b1c8-edd00b114317", + "metadata": {}, + "source": [ + "For more details: [https://docs.julialang.org/en/v1/manual/control-flow/](https://docs.julialang.org/en/v1/manual/control-flow/)." + ] + }, + { + "cell_type": "markdown", + "id": "e4510840-0890-4217-8a8c-c24aa5d3405b", + "metadata": {}, + "source": [ + "## Iterations\n", + "\n", + "Julia implements the standard `for` and `while` constructs." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9632f210-c713-4829-8187-cf5554adad87", + "metadata": {}, + "outputs": [], + "source": [ + "for i in 1:5\n", + " println(\"Hello from number $i\")\n", + "end" + ] + }, + { + "cell_type": "markdown", + "id": "f00caf15-4992-4c0a-8324-9d2be966346d", + "metadata": {}, + "source": [ + "Where the `1:5` is a `Range`-object, but it could be any iterable. There are a few syntax variations, including:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "70a9f620-e4ce-4367-b0f5-de37db3f48b5", + "metadata": {}, + "outputs": [], + "source": [ + "result = 0\n", + "# To get ∈ write \\in and then press TAB\n", + "for j ∈ 1:0.5:3 # Note the step parameter\n", + " result += j\n", + "end\n", + "println(result)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e83b2d88-b0f2-43f1-9187-65fbc75f0d3b", + "metadata": {}, + "outputs": [], + "source": [ + "n = 10\n", + "while n > 0\n", + " print(n, \" \")\n", + " n = n - 1\n", + "end" + ] + }, + { + "cell_type": "markdown", + "id": "f19d5051-ce82-49cc-80aa-2434a6adc9d0", + "metadata": {}, + "source": [ + "The loops can be further controlled with the `break` and `continue` keywords." + ] + }, + { + "cell_type": "markdown", + "id": "d0ebce97-3054-4eba-821d-92f27793d752", + "metadata": {}, + "source": [ + "Sometimes you don’t know it’s time to end a loop until you get half way through the body. In that case you can use the `break` statement to jump out of the loop." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9bb642e3-e3b1-488d-939f-6932feb62479", + "metadata": {}, + "outputs": [], + "source": [ + "while true\n", + " print(\"> \")\n", + " line = readline()\n", + " if line == \"done\"\n", + " break\n", + " end\n", + " println(line)\n", + "end\n", + "println(\"Done!\")" + ] + }, + { + "cell_type": "markdown", + "id": "98eee547-21fe-4022-bde5-b02ababa26dd", + "metadata": {}, + "source": [ + "The `break` statement exits the loop. When a `continue` statement is encountered inside a loop, control jumps to the beginning of the loop for the next iteration, skipping the execution of statements inside the body of the loop for the current iteration. For example:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7f1c2595-8836-4308-9769-f4140d402582", + "metadata": {}, + "outputs": [], + "source": [ + "for i in 1:10\n", + " if i % 3 == 0\n", + " continue\n", + " end\n", + " print(i, \" \")\n", + "end" + ] + }, + { + "cell_type": "markdown", + "id": "b8eac9e9-dff9-4b86-88a7-e14f27b7f677", + "metadata": {}, + "source": [ + "For more detials: [https://docs.julialang.org/en/v1/base/collections/#lib-collections-iteration](https://docs.julialang.org/en/v1/base/collections/#lib-collections-iteration)." + ] + }, + { + "cell_type": "markdown", + "id": "990cefae-abfe-4649-8d68-3fac1b1e268b", + "metadata": {}, + "source": [ + "### Exercises" + ] + }, + { + "cell_type": "markdown", + "id": "bdb2eef9-bdee-4cf3-8bab-d6c1d46ecc2f", + "metadata": {}, + "source": [ + "The mathematician Srinivasa Ramanujan found an infinite series that can be used to generate a numerical approximation of 1/π\n", + "\n", + "$$ \\frac{1}{\\pi} = \\frac{2\\sqrt{2}}{9801} \\sum_{k=0}^\\infty \\frac{(4k)! (1103 + 26390 k)}{(k!)^4 396^{4 k}}$$\n", + "\n", + "Use this formula to compute an estimate of π. It should use a while loop ot compute terms of the summation untile the last term is smaller than 1e-15. Afterwards, you can check the result by comparing it to π (to get π in Julia, write \\pi and then press TAB). Hint: use the builtin function `factorial`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "dbe40300-8333-4271-aa43-49f973fa03a6", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "id": "d4a870c3-7679-4775-94ce-4e7266a2bebe", + "metadata": {}, + "source": [ + "## Functions" + ] + }, + { + "cell_type": "markdown", + "id": "682a3feb-0b82-479d-9803-3011a1e6e521", + "metadata": {}, + "source": [ + "We have already seen one example of a function call:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "addaa346-7a88-4c18-9f1e-295665959a9d", + "metadata": {}, + "outputs": [], + "source": [ + "println(\"Hello, World!\")" + ] + }, + { + "cell_type": "markdown", + "id": "3434842c-2af0-4f6a-a70b-a59fb8fcc4af", + "metadata": {}, + "source": [ + "The name of the function is println. The expression in parentheses is called the argument of the function.\n", + "It is common to say that a function “takes” an argument and “returns” a result. The result is also called the return value." + ] + }, + { + "cell_type": "markdown", + "id": "f63d270a-7149-4ffd-bc31-f746560a37ac", + "metadata": {}, + "source": [ + "Julia provides functions that convert values from one type to another. The parse function takes a string and converts it to any number type, if it can, or complains otherwise:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1f05465a-4863-4205-9c73-26f0e93f049b", + "metadata": {}, + "outputs": [], + "source": [ + "parse(Int64, \"32\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e6ac9994-9cbb-4004-889d-a657b8396063", + "metadata": {}, + "outputs": [], + "source": [ + "parse(Int64, \"Hello\")" + ] + }, + { + "cell_type": "markdown", + "id": "793c9620-7b6e-443c-8765-8136fbfcb071", + "metadata": {}, + "source": [ + "Julia provides several mathematical functions.\n", + " - abs, sqrt, cbrt, exp, log, log10, log2\n", + " - sin, cos, tan, asin, acos, atan\n", + " - sinh, cosh, tanh, asinh, acosh, atanh\n", + " - floor: Largest integer not greater than x.\n", + " - ceil: Smallest integer not less than x.\n", + " - round: Nearest integer to x.\n", + " - trunc: Integer part of x.\n", + "\n", + "For more details: [https://docs.julialang.org/en/v1/base/math/#Mathematical-Functions](https://docs.julialang.org/en/v1/base/math/#Mathematical-Functions)." + ] + }, + { + "cell_type": "markdown", + "id": "d048851b-8eac-4dc3-81b7-ea1d625a1db2", + "metadata": {}, + "source": [ + "So far, we have only been using the functions that come with Julia, but it is also possible to add new functions. \n", + "Defining functions follows a rather intuitive syntax. The value obtained by evaluating the last expression of a `function` block will be automatically returned:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fd2f4828-47f5-4df4-b5bd-a42625487b5a", + "metadata": {}, + "outputs": [], + "source": [ + "function mymult(x, y)\n", + " x * y\n", + "end" + ] + }, + { + "cell_type": "markdown", + "id": "08bab11e-df61-4906-a925-b93184e5c600", + "metadata": {}, + "source": [ + "For one-line functions one may also use a convenient short-hand:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5ed8292a-96e2-49ad-8f00-3c07b9483637", + "metadata": {}, + "outputs": [], + "source": [ + "mysquare(x) = mymult(x, x)" + ] + }, + { + "cell_type": "markdown", + "id": "13b7892e-df8a-462f-a84c-107276d8e499", + "metadata": {}, + "source": [ + "Both such functions are fully generic in the argument types" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "49ceeeff-5291-460d-800d-5ed11a03b13e", + "metadata": {}, + "outputs": [], + "source": [ + "@show mysquare(2) # Use integer arithmetic\n", + "@show mymult(-1, 3. + 2im) # Use complex arithmetic\n", + "@show mysquare(\" abc \"); # Use string concatenation" + ] + }, + { + "cell_type": "markdown", + "id": "15ece147-0384-4c1b-a8c3-d11a795bd1b7", + "metadata": {}, + "source": [ + "Notice, that for each type combination a separate piece of code will be compiled even though we only *defined* the functionality a single time. This compilation takes place on first use of a particular tuple of types." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7e5dcfeb-960a-47f3-b2f8-f6f0906d2f24", + "metadata": {}, + "outputs": [], + "source": [ + "mymult" + ] + }, + { + "cell_type": "markdown", + "id": "934dc8e8-564b-4566-9eb0-a96df39f0870", + "metadata": {}, + "source": [ + "and may be passed around to other functions, for example:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "171b1a83-c076-4ac4-a309-9d607ea0b5a4", + "metadata": {}, + "outputs": [], + "source": [ + "\"\"\"The fold function, applying f from the left and accumulating the results\"\"\"\n", + "function myfold(f, x, y, z)\n", + " f(f(x, y), z)\n", + "end\n", + "myfold(mymult, \"Hello\", \" Julia \", \"World\")" + ] + }, + { + "cell_type": "markdown", + "id": "f31327e4-5d69-4dfb-a4bf-ed1e419b1be3", + "metadata": {}, + "source": [ + "Julia makes a distinction between **functions** and **methods**. Roughly speaking **function**s specify *what* is done and **methods** specify *how* this is done.\n", + "\n", + "Methods are concrete implementations in form of a list of Julia expressions to be executed, when the function name is used in the code. Multiple methods may be defined for the same function name. They differ in the number of arguments or in the supported argument types (more on this in the next notebook). When a particular function name is used in the code, Julia looks at the types of the arguments and uses this information to **dispatch** to the best-fitting method. \n", + "\n", + "For our `myfold` example, one could easily imagine a few more method implementations, for example:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c249f818-6544-42fe-b387-34058e5f5890", + "metadata": {}, + "outputs": [], + "source": [ + "myfold(f, x) = x\n", + "myfold(f, x, y) = f(x, y)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "88f62159-2a1b-4a5a-8434-0e91810f2c69", + "metadata": {}, + "outputs": [], + "source": [ + "methods(myfold)" + ] + }, + { + "cell_type": "markdown", + "id": "879d9441-ece1-4f07-a496-6aef71fd2e91", + "metadata": {}, + "source": [ + "So now `myfold` works transparently with 1, 2 or 3 arguments:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d67f9c21-2c5c-43fd-a7e4-a4ce74281bf0", + "metadata": {}, + "outputs": [], + "source": [ + "@show myfold(mymult, 2., 3.)\n", + "@show myfold(+, 1)\n", + "@show myfold(==, false, false, true)" + ] + }, + { + "cell_type": "markdown", + "id": "59fa4c2a-a1fa-4a1b-9529-68f821589206", + "metadata": {}, + "source": [ + "We can also check which method is actually employed using the `@which` macro:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0fa105fb-b3ad-405a-85f1-598a12cbc655", + "metadata": {}, + "outputs": [], + "source": [ + "@which myfold(*, 1, 2)" + ] + }, + { + "cell_type": "markdown", + "id": "73fa3be7-67a8-4817-9d94-e04765513dd3", + "metadata": {}, + "source": [ + "Standard functions (like `+` or `*`) are by no means special and behave exactly the same way as custom functions ... including the ability to define new methods for them:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d771af33-5174-4a95-b8e3-ac1c29eb71e9", + "metadata": {}, + "outputs": [], + "source": [ + "import Base: + # we have to import functions to override/extend them\n", + "+(x::String, y::String) = x * \" \" * y" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "32429003-4879-4a37-ad3c-153857a360dd", + "metadata": {}, + "outputs": [], + "source": [ + "\"Hello\" + \"World!\"" + ] + }, + { + "cell_type": "markdown", + "id": "8fdf6362-7ca3-4d32-a542-26df56b83108", + "metadata": {}, + "source": [ + "(**Important note:** Since we neither own the `+` function nor the `String` type, this is known as **type piracy** and should in general be avoided!)" + ] + }, + { + "cell_type": "markdown", + "id": "89ffcdef-cf06-438f-8448-4bf6dfd1af7e", + "metadata": {}, + "source": [ + "Now standard functions relying on `+` just magically work:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "75b4afeb-a3f4-40d7-8b23-b961b01c41bc", + "metadata": {}, + "outputs": [], + "source": [ + "sum([\"a\", \"b\", \"c\", \"d\", \"e\"])" + ] + }, + { + "cell_type": "markdown", + "id": "d8edaaf0-3de7-4a63-b0bd-bff53ba060f4", + "metadata": {}, + "source": [ + "Variables and parameters are local, they exist only inside the functions where they are defined:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d02e6bca-6723-4a05-82ee-1f30ba127bd5", + "metadata": {}, + "outputs": [], + "source": [ + "function multiply_and_print(a, b)\n", + " product = a * b\n", + " println(product)\n", + "end\n", + "\n", + "multiply_and_print(2, 3)\n", + "println(product)" + ] + }, + { + "cell_type": "markdown", + "id": "29968f96-5766-4cb7-8538-3bef9aeb8cc9", + "metadata": {}, + "source": [ + "It may not be clear why it is worth the trouble to divide a program into functions. There are several reasons:\n", + " - Creating a new function gives you an opportunity to name a group of statements, which makes your program easier to read and debug.\n", + " - Functions can make a program smaller by eliminating repetitive code. Later, if you make a change, you only have to make it in one place.\n", + " - Dividing a long program into functions allows you to debug the parts one at a time and then assemble them into a working whole.\n", + " - Well-designed functions are often useful for many programs. Once you write and debug one, you can reuse it.\n", + " - In Julia, functions can improve performance a lot." + ] + }, + { + "cell_type": "markdown", + "id": "7780ae66-db68-48c1-ba62-a883406f1f1c", + "metadata": {}, + "source": [ + "More details: [https://docs.julialang.org/en/v1/manual/methods/](https://docs.julialang.org/en/v1/manual/methods/)" + ] + }, + { + "cell_type": "markdown", + "id": "d914b36b-8b05-4c68-bf57-1fc74aeb26df", + "metadata": {}, + "source": [ + "### Exercises" + ] + }, + { + "cell_type": "markdown", + "id": "247215e4-47e1-4eb6-978b-a09f14478bb8", + "metadata": {}, + "source": [ + " - Write a function `printgrid` that draws a grid like the following:" + ] + }, + { + "cell_type": "markdown", + "id": "1704f451-9500-41c5-b74b-4a2b4a7b910f", + "metadata": {}, + "source": [ + " + - - - - + - - - - +\n", + " | | |\n", + " | | |\n", + " | | |\n", + " | | |\n", + " + - - - - + - - - - +\n", + " | | |\n", + " | | |\n", + " | | |\n", + " | | |\n", + " + - - - - + - - - - +" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "58ef3248-f85e-4825-bf10-02cee3e068cb", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "id": "e6a58742-9d24-47a5-aa68-73d44ca05127", + "metadata": {}, + "source": [ + " - Write a function that draws a similar grid with four rows and four columns." + ] + }, + { + "cell_type": "markdown", + "id": "b953857f-e8d7-47aa-bc8d-8e2bd1cd20fd", + "metadata": {}, + "source": [ + "Tips:\n", + " - To print more than one value on a line, you can print a comma-separated sequence of values: println(\"+\", \"-\").\n", + " - The function print does not advance to the next line." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1ca1789d-eddb-4f41-9ad9-9259c6f22a14", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "id": "2ebc911c-7fe0-4d7f-ab5d-d8084f25a93d", + "metadata": {}, + "source": [ + "### Recursive functions\n", + "\n", + "It is legal for one function to call another; it is also legal for a function to call itself. It may not be obvious why that is a good thing, but it turns out to be one of the most magical things a program can do. For example, look at the following function:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e578011e-d0de-4f86-8c2c-a8408454d3ac", + "metadata": {}, + "outputs": [], + "source": [ + "function countdown(n)\n", + " if n ≤ 0\n", + " println(\"Blastoff!\")\n", + " else\n", + " print(n, \" \")\n", + " countdown(n-1)\n", + " end\n", + "end" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3af51513-c92e-4488-b2fe-243e2fef6b95", + "metadata": {}, + "outputs": [], + "source": [ + "countdown(10)" + ] + }, + { + "cell_type": "markdown", + "id": "c59c0f54-d967-4416-b57c-e855dfc2c350", + "metadata": {}, + "source": [ + "If a recursion never reaches a base case, it goes on making recursive calls forever, and the program never terminates. This is known as infinite recursion, and it is generally not a good idea. Here is a minimal program with an infinite recursion: " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "13a4a762-6584-47ab-9fb5-428557770d15", + "metadata": {}, + "outputs": [], + "source": [ + "function recurse()\n", + " recurse()\n", + "end" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0dde579f-6b12-4072-aa62-aeee3a970503", + "metadata": {}, + "outputs": [], + "source": [ + "recurse()" + ] + }, + { + "cell_type": "markdown", + "id": "22c8c79d-6d41-4758-9550-aaab4f1dc1b1", + "metadata": {}, + "source": [ + "### Exercises\n", + " - Write a recursive function to compute the factorial of a number." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f4102487-011e-474f-ab79-3d7db1d3bbd9", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "id": "d9c31712-941c-4611-99e5-b33cdb12e28f", + "metadata": {}, + "source": [ + " - Then write a function that computes binomial coefficients\n", + "$$ \\left(\\begin{array}{c} n \\\\ k \\end{array}\\right) = \\frac{n!}{k! (n-k)!} $$\n", + " by calling the function of the previous points." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b54c877e-5494-4657-ba7f-208bdc301225", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "id": "4509db3f-8060-46ca-89ac-824c16f5751c", + "metadata": {}, + "source": [ + "- Use the two functions to compute\n", + "$$ 15! \\qquad \\left(\\begin{array}{c} 5 \\\\ 2 \\end{array}\\right) \\qquad \\left(\\begin{array}{c} 5 \\\\ 3 \\end{array}\\right) $$" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fb02aad5-d9d4-4f0d-8118-b02b73506b89", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "id": "240cc4bd-3e45-45b8-ad98-170dbb68f78d", + "metadata": {}, + "source": [ + "### Keywords argument\n", + "\n", + "Function arguments can be either position based (like what we saw so far) or keyword based, like in the following example." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "30ddeb3b-be35-40eb-8491-1269a4e19f62", + "metadata": {}, + "outputs": [], + "source": [ + "function greet(name; greeting=\"Hello\")\n", + " println(\"$(greeting), $(name)!\")\n", + "end" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b39f22b1-4a1b-4afd-b6db-041bd7150b66", + "metadata": {}, + "outputs": [], + "source": [ + "greet(\"Michele\")\n", + "greet(\"Lambert\"; greeting=\"Hallo\")\n", + "greet(\"YingXing\"; greeting=\"你好\")" + ] + }, + { + "cell_type": "markdown", + "id": "52b90aa8-4b19-4371-8fae-2121a78fbb96", + "metadata": {}, + "source": [ + "This is quite convenient in the following cases:\n", + " - to set a default behavior of the function, while retaining the possibility to finely control it.\n", + " - to add at a later point in time new functionality, without breaking retrocompatibility." + ] + }, + { + "cell_type": "markdown", + "id": "c939f951-2aaf-4e39-a60f-df7600af1d8f", + "metadata": {}, + "source": [ + "## Further Exercises" + ] + }, + { + "cell_type": "markdown", + "id": "59e2e997-42f7-426c-bfd0-233724704117", + "metadata": {}, + "source": [ + " - Create a function called `fibonacci_sum` that takes a positive integer n as input. This function should return the sum of the first n terms of the Fibonacci sequence." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7ca7c936-fb80-4aed-9788-75a55bb207ad", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "id": "49fd546f-009d-46ff-af61-6954000bce5f", + "metadata": {}, + "source": [ + " - Write a function that converts a Celsius temperature in Fahrenheit and returns the result. Additionally, if the temperature is below freezing (0°C), the program should print a message indicating that it's below freezing." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a30a1812-6116-4441-8786-7450c60ef354", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "id": "e2c81cc5-7d0d-4a5a-ba69-81686648df90", + "metadata": {}, + "source": [ + " - Write a function which analyzes a sentence. The function should then count and display the number of vowels (both upper and lower case) in the sentence." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "af0e28bd-2b3f-41af-aa92-456e29d50679", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Julia 1.9.3", + "language": "julia", + "name": "julia-1.9" + }, + "language_info": { + "file_extension": ".jl", + "mimetype": "application/julia", + "name": "julia" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/2_Advanced_Data_Types_de.ipynb b/2_Advanced_Data_Types_de.ipynb new file mode 100644 index 0000000000000000000000000000000000000000..36325fcd5eb2c8a6f0f1ce48725cdaf7fefb8dad --- /dev/null +++ b/2_Advanced_Data_Types_de.ipynb @@ -0,0 +1,1140 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "5de78ecc-bbde-49ff-b618-b8c8c440ce47", + "metadata": {}, + "source": [ + "# Fortgeschrittene Datentypen" + ] + }, + { + "cell_type": "markdown", + "id": "8ffb53e2-1813-4fdf-962e-e066bc9b737c", + "metadata": {}, + "source": [ + "## Zuordnungstabellen (assoziative Listen)" + ] + }, + { + "cell_type": "markdown", + "id": "548487ed-dc9d-4404-a2ab-451c0ea742e4", + "metadata": {}, + "source": [ + "Eine Zuordnungstabelle enthält eine Sammlung von Indizes, die als Schlüssel bezeichnet werden, und eine Sammlung von Werten. Jeder Schlüssel ist mit einem einzigen Wert verbunden. Die Zuordnung eines Schlüssels und eines Wertes wird als Schlüssel-Wert-Paar oder manchmal als Element bezeichnet.\n", + "\n", + "Die Funktion `Dict` erstellt ein neues Wörterbuch ohne Elemente. Da `Dict` der Name einer integrierten Funktion ist, sollte man vermeiden ihn als Variablenname zu verwenden." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "59ae8d17-a6f6-4210-95bc-0e7492bc8a7a", + "metadata": {}, + "outputs": [], + "source": [ + "eng2de = Dict()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "28490ea3-c4d3-4e4d-915f-612ad36c9472", + "metadata": {}, + "outputs": [], + "source": [ + "eng2de[\"one\"] = \"ein\";" + ] + }, + { + "cell_type": "markdown", + "id": "09b62b4d-748b-4e1d-91f2-7db610ad02ac", + "metadata": {}, + "source": [ + "Du kannst auch eine Zuordnungstabelle mit Elementen wie folgt initialisieren:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "92fc203b-4ba8-432a-a541-c4ccf3292195", + "metadata": {}, + "outputs": [], + "source": [ + "eng2de = Dict(\"one\" => \"ein\", \"two\" => \"zwei\", \"three\" => \"drei\")" + ] + }, + { + "cell_type": "markdown", + "id": "809e7c99-22f0-4440-921d-e5904cadc8a4", + "metadata": {}, + "source": [ + "Wörterbücher sind veränderbar, was bedeutet, dass es immer möglich ist, ihre Elemente zu ändern, neue Schlüssel-Wert-Paare hinzuzufügen oder bestehende zu entfernen." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "22b295dc-994e-4bbc-ac8d-da5ab9e73493", + "metadata": {}, + "outputs": [], + "source": [ + "eng2de[\"four\"] = \"VIER\"\n", + "@show eng2de\n", + "eng2de[\"four\"] = \"vier\"\n", + "@show eng2de\n", + "delete!(eng2de, \"four\")\n", + "@show eng2de;" + ] + }, + { + "cell_type": "markdown", + "id": "d8b4ee03-5592-4567-883b-e0842fefeff4", + "metadata": {}, + "source": [ + "Im Allgemeinen ist die Reihenfolge der Schlüssel-Wert-Paare unvorhersehbar. Dies ist jedoch nicht wichtig, da die Werte immer mithilfe der Schlüssel abgerufen werden." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e9e4c5b9-9539-4294-a6ec-0a29fb76bf7b", + "metadata": {}, + "outputs": [], + "source": [ + "eng2de[\"two\"]" + ] + }, + { + "cell_type": "markdown", + "id": "84cf8b52-f061-4b28-a327-bc527820517c", + "metadata": {}, + "source": [ + "Wenn der Schlüssel nicht im Wörterbuch vorhanden ist, tritt eine Fehlermeldung auf:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8221269b-7a8f-4cfd-ab8e-0aa4fd6c962d", + "metadata": {}, + "outputs": [], + "source": [ + "eng2de[\"four\"]" + ] + }, + { + "cell_type": "markdown", + "id": "f83d51c5-2c1d-4449-8cd5-e80f224b9a76", + "metadata": {}, + "source": [ + "Die Funktion `length` funktioniert auch bei Zuordnungstabellen; sie gibt die Anzahl der Schlüssel-Wert-Paare zurück:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0e242667-b921-4242-bdcc-cbcac14909b2", + "metadata": {}, + "outputs": [], + "source": [ + "length(eng2de)" + ] + }, + { + "cell_type": "markdown", + "id": "b4ac7b46-9fc0-47fd-b6c0-c97791517b51", + "metadata": {}, + "source": [ + "Die Funktion `keys` gibt eine Sammlung mit den Schlüsseln des Wörterbuchs zurück:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3236f973-d3fa-42ba-a1c0-41e0002446cb", + "metadata": {}, + "outputs": [], + "source": [ + "keys(eng2de)" + ] + }, + { + "cell_type": "markdown", + "id": "f9bc6fe5-3f7a-458e-942a-11bd3e83dcc6", + "metadata": {}, + "source": [ + "Nun kannst du den Operator `∈` verwenden, um zu sehen, ob etwas als Schlüssel im Wörterbuch vorhanden ist:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1fdeb10c-0d84-4c22-b734-d68e2eafe375", + "metadata": {}, + "outputs": [], + "source": [ + "@show \"one\" ∈ keys(eng2de)\n", + "@show \"four\" ∈ keys(eng2de);" + ] + }, + { + "cell_type": "markdown", + "id": "864d141e-6cd2-45e6-95fe-e84cca35cf70", + "metadata": {}, + "source": [ + "Um zu überprüfen, ob etwas als Wert in einem Wörterbuch vorhanden ist, kannst du die Funktion `values` verwenden, die eine Sammlung von Werten zurückgibt, und dann den Operator `∈` verwenden:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ab90dad1-61d0-4dbd-b829-a354c13fcb71", + "metadata": {}, + "outputs": [], + "source": [ + "@show \"ein\" ∈ values(eng2de)\n", + "@show \"vier\" ∈ values(eng2de);" + ] + }, + { + "cell_type": "markdown", + "id": "5b255b31-8aca-49b4-a95f-302c59baa975", + "metadata": {}, + "source": [ + "### Schleifen über Zuordnungstabellen\n", + "\n", + "Du kannst die Schlüssel der Zuordnungstabelle in einer `for`-Schleife durchlaufen." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e7062d3f-2125-4ecd-ab13-d04944a71fe1", + "metadata": {}, + "outputs": [], + "source": [ + "function print_dictionary(dic)\n", + " for key in keys(dic)\n", + " println(key, \" \", dic[key])\n", + " end\n", + "end\n", + "\n", + "print_dictionary(eng2de)" + ] + }, + { + "cell_type": "markdown", + "id": "a6b3285a-58f6-41b6-8755-2732a367424e", + "metadata": {}, + "source": [ + "Auch hier sind die Schlüssel in keiner bestimmten Reihenfolge. Um die Schlüssel in alphabetisch sortierter Reihenfolge zu durchlaufen, kannst du `sort` und `collect` kombinieren:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6d52aeba-3c7e-405c-bcfe-d76e37e94f51", + "metadata": {}, + "outputs": [], + "source": [ + "function print_dictionary_sorted(dic)\n", + " for key in sort(collect(keys(dic)))\n", + " println(key, \" \", dic[key])\n", + " end\n", + "end\n", + "\n", + "print_dictionary_sorted(eng2de)" + ] + }, + { + "cell_type": "markdown", + "id": "964165ee-4d0d-4122-b6b2-d3926101cab2", + "metadata": {}, + "source": [ + "### Übung\n", + " - Schreibe eine Funktion, die bei Eingabe eines Strings zählt, wie oft jeder Buchstabe vorkommt. Verwende ein Wörterbuch." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "aba1978b-e675-48a7-89aa-75553db70537", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "id": "0acaa2f9-372c-4a3e-be01-27cfe2853fdb", + "metadata": {}, + "source": [ + "## Tupel und benannte Tupel" + ] + }, + { + "cell_type": "markdown", + "id": "68ea4303-ce3c-4647-8e9f-89afd0a6a670", + "metadata": {}, + "source": [ + "Ein Tupel ist eine Sequenz von Werten. Die Werte können beliebigen Typs sein und sie werden durch Ganzzahlen indexiert. Die Tupel sind unveränderlich und jedes Element kann seinen eigenen Typ haben." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8502cf2e-8bea-4707-811c-f4e6e1de3c8f", + "metadata": {}, + "outputs": [], + "source": [ + "t = 'a', 'b', 'c', 'd', 'e'" + ] + }, + { + "cell_type": "markdown", + "id": "2632b11b-de4b-4f21-bcc6-06a32517c121", + "metadata": {}, + "source": [ + "Obwohl es nicht notwendig ist, ist es üblich, Tupel in Klammern zu setzen:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bfa31b99-bf9d-49bb-babc-fe8a65248429", + "metadata": {}, + "outputs": [], + "source": [ + "t = ('a', 'b', 'c', 'd', 'e')" + ] + }, + { + "cell_type": "markdown", + "id": "86fa8b6b-bbbf-4c9c-a5c0-63b00b2c59cb", + "metadata": {}, + "source": [ + "Um ein Tupel mit einem einzigen Element zu erstellen, musst du ein abschließendes Komma setzen:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cb1bea15-2b80-43b2-be8e-27507d550fca", + "metadata": {}, + "outputs": [], + "source": [ + "t1 = ('a',)\n", + "@show typeof(t1)\n", + "\n", + "t2 = ('a')\n", + "@show typeof(t2);" + ] + }, + { + "cell_type": "markdown", + "id": "d6f34b5b-2aaa-49db-b2a8-d5891fe33ee1", + "metadata": {}, + "source": [ + "Eine andere Möglichkeit, ein Tupel zu erstellen, ist die integrierte Funktion `tuple`. Ohne Argument erstellt sie ein leeres Tupel:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "952acafe-ca5d-4b58-8969-224b0fe3a28f", + "metadata": {}, + "outputs": [], + "source": [ + "t3 = tuple()\n", + "@show typeof(t3)\n", + "\n", + "t4 = tuple(1, 'a', π, 12.0)\n", + "@show typeof(t4);" + ] + }, + { + "cell_type": "markdown", + "id": "efc3d061-7e93-4863-a802-a7cdb869af7e", + "metadata": {}, + "source": [ + "Mit dem eckigen Klammern-Operator ist es möglich, auf ein Element zuzugreifen. Beachte, dass in Julia das erste Element, anders als in anderen Programmiersprachen (zum Beispiel C, C++, Python), mit 1 indexiert wird." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9817c28f-428d-4d5b-8384-608f9b4d763d", + "metadata": {}, + "outputs": [], + "source": [ + "t4[2]" + ] + }, + { + "cell_type": "markdown", + "id": "17a0f0ee-e03f-4669-a5f1-889d875577d9", + "metadata": {}, + "source": [ + "Es ist auch möglich, mehrere Elemente mithilfe von Slices zu erhalten." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c48ac07f-3a4e-4bb8-9551-2973ea8d2f9c", + "metadata": {}, + "outputs": [], + "source": [ + "@show t4[1:3];" + ] + }, + { + "cell_type": "markdown", + "id": "d0f25a1f-0a4c-4ab4-a339-f5ba64806681", + "metadata": {}, + "source": [ + "Aber wenn du versuchst, eines der Elemente des Tupels zu ändern, tritt ein Fehler auf:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cfc94cc9-832c-45d2-85b8-aaf789f33f6a", + "metadata": {}, + "outputs": [], + "source": [ + "t4[2] = 'b'" + ] + }, + { + "cell_type": "markdown", + "id": "d956168e-36e4-4abb-a3d6-3c53a857e78d", + "metadata": {}, + "source": [ + "Da Tupel unveränderlich sind, kannst du die Elemente nicht ändern." + ] + }, + { + "cell_type": "markdown", + "id": "6a115819-54fd-4550-b097-59fea3ecb523", + "metadata": {}, + "source": [ + "Genau genommen kann eine Funktion nur einen Wert zurückgeben, aber wenn der Wert ein Tupel ist, hat dies den gleichen Effekt wie das Zurückgeben mehrerer Werte. Zum Beispiel, wenn du zwei Ganzzahlen teilen und den Quotienten und den Rest berechnen möchtest, ist es ineffizient, zuerst x ÷ y und dann x % y zu berechnen. Es ist besser, beides gleichzeitig zu berechnen.\n", + "\n", + "Die integrierte Funktion `divrem` nimmt zwei Argumente entgegen und gibt ein Tupel aus zwei Werten zurück, dem Quotienten und dem Rest. Du kannst das Ergebnis als Tupel speichern:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d1dde137-036f-4b93-8010-13b3e835ebd8", + "metadata": {}, + "outputs": [], + "source": [ + "t = divrem(7, 3)" + ] + }, + { + "cell_type": "markdown", + "id": "9cd48d9c-cf1d-4546-a2c0-4bb54a42e1e8", + "metadata": {}, + "source": [ + "Alternativ können wir die Zuweisung als Tupel verwenden, um die Elemente getrennt zu speichern:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c4969556-7945-43c9-8b96-1ea1032cbb3c", + "metadata": {}, + "outputs": [], + "source": [ + "q, r = divrem(7, 3)\n", + "\n", + "@show q r;" + ] + }, + { + "cell_type": "markdown", + "id": "e4177fab-a386-4274-8657-bbc6698ec1e5", + "metadata": {}, + "source": [ + "### Sammeln und verteilen\n", + "\n", + "Funktionen können eine variable Anzahl von Argumenten entgegennehmen. Ein Parametername, der mit `...` endet, sammelt die Argumente in ein Tupel. Zum Beispiel nimmt `printall` eine beliebige Anzahl von Argumenten entgegen und gibt sie nacheinander aus:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "43f8c7ad-5ac2-425e-a50f-c45624bb3d8a", + "metadata": {}, + "outputs": [], + "source": [ + "function printall(args...)\n", + " for arg in args\n", + " println(arg)\n", + " end\n", + "end\n", + "\n", + "printall(1)\n", + "printall(1, 2.0, '3')" + ] + }, + { + "cell_type": "markdown", + "id": "28b3cd91-bf05-43bc-a253-2bee077a1df1", + "metadata": {}, + "source": [ + "Das Gegenstück zu \"sammeln\" ist \"verteilen\". Wenn du eine Sequenz von Werten hast und sie als mehrere Argumente an eine Funktion übergeben möchtest, kannst du den Operator `...` verwenden. Zum Beispiel nimmt `divrem` genau zwei Argumente an; es funktioniert nicht mit einem Tupel:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bf55fc10-8432-41e3-bd6c-2244c8c96513", + "metadata": {}, + "outputs": [], + "source": [ + "t = (7, 3)\n", + "divrem(t)" + ] + }, + { + "cell_type": "markdown", + "id": "db3cd00d-d41c-4f68-95d4-c4e5b283734a", + "metadata": {}, + "source": [ + "Wenn du aber das Tupel verteilst, funktioniert es:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e7df53bc-6b2d-4501-9ca8-61e3cb79eb1a", + "metadata": {}, + "outputs": [], + "source": [ + "t = (7, 3)\n", + "divrem(t...)" + ] + }, + { + "cell_type": "markdown", + "id": "dad5d7bf-0dd5-450b-90f3-7768f2d91c18", + "metadata": {}, + "source": [ + "### Zuordnungstabellen und Tupel" + ] + }, + { + "cell_type": "markdown", + "id": "3a38cabd-b056-4140-a75c-e0fa383a2a74", + "metadata": {}, + "source": [ + "Zuordnungstabellen können als Iteratoren verwendet werden, um die Schlüssel-Wert-Paare zu durchlaufen. Du kannst es in einer `for`-Schleife wie folgt verwenden:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ed483334-36d0-4700-b178-cd9dc5f12189", + "metadata": {}, + "outputs": [], + "source": [ + "d = Dict('a'=>1, 'b'=>2, 'c'=>3);\n", + "for (key, value) in d\n", + " println(key, \" \", value)\n", + "end" + ] + }, + { + "cell_type": "markdown", + "id": "5a012731-cf42-487b-9d02-4a4b1d0475c0", + "metadata": {}, + "source": [ + "Es ist üblich, Tupel als Schlüssel in Zuordnungstabellen zu verwenden. Zum Beispiel könnte ein Telefonverzeichnis Nachname-Vorname-Paare auf Telefonnummern abbilden. Angenommen, wir haben last, first und number definiert, könnten wir schreiben:" + ] + }, + { + "cell_type": "markdown", + "id": "e5462d35-fa68-42d8-ba00-c5dd1747c557", + "metadata": {}, + "source": [ + "`directory[last, first] = number`" + ] + }, + { + "cell_type": "markdown", + "id": "7bd0a942-de38-4c9e-96df-a786fa814254", + "metadata": {}, + "source": [ + "### Benannte Tupel" + ] + }, + { + "cell_type": "markdown", + "id": "2284786f-cb8b-4173-944a-e50d79ceca2d", + "metadata": {}, + "source": [ + "Benannte Tupel sind ein besonderer Tupeltyp in Julia, bei dem jedem Element ein spezifischer Name zugeordnet ist. Dies ermöglicht es dir, auf Elemente anhand ihrer Namen zuzugreifen, was den Code lesbarer und selbsterklärender macht." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "78fb5959-407a-4128-9287-bb9d455f22dc", + "metadata": {}, + "outputs": [], + "source": [ + "person = (name = \"Michele\", age = 28, city = \"Stuttgart\")" + ] + }, + { + "cell_type": "markdown", + "id": "01e99a5c-f331-4ad6-95e0-e403b8ad327b", + "metadata": {}, + "source": [ + "Benannte Tupel sind unveränderlich, aber es ist möglich, den Inhalt zu aktualisieren oder neue Elemente hinzuzufügen, indem eine neue Version erstellt wird. Zum Beispiel:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ecd22e07-5ba3-4f11-bc77-d967a6fc3fe8", + "metadata": {}, + "outputs": [], + "source": [ + "updated_person = (person..., age = 29)\n", + "updated_person = (person..., number = \"0711 ...\")" + ] + }, + { + "cell_type": "markdown", + "id": "70061322-9435-496a-ac0d-c026f41e5936", + "metadata": {}, + "source": [ + "### Übung\n", + " - Schreibe eine Funktion `swap_first_last`, die ein Tupel entgegennimmt und ein neues Tupel zurückgibt, bei dem das erste und das letzte Element vertauscht sind. Tipp: Verwende eine Kombination des `...`-Operators und des Slices `[2:end-1]`.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3721b654-b182-426d-b799-a69e0b53a550", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "id": "5629a477-5d19-43a2-8bb4-e10b10f2ffde", + "metadata": {}, + "source": [ + "## Objekte und Strukturen" + ] + }, + { + "cell_type": "markdown", + "id": "18412e4f-e5fb-4a92-a083-ac2e5b58cde3", + "metadata": {}, + "source": [ + "Zu diesem Zeitpunkt weißt du bereits, wie man Funktionen verwendet, um Code zu organisieren, und integrierte Typen, um Daten zu organisieren. Der nächste Schritt ist zu lernen, wie man eigene Typen erstellt, um sowohl Code als auch Daten zu organisieren.\n", + "\n", + "Wir haben viele der integrierten Typen von Julia verwendet; jetzt werden wir einen neuen Typ definieren. Als Beispiel werden wir einen Typ namens Punkt erstellen, der einen Punkt im zweidimensionalen Raum repräsentiert.\n", + "\n", + "Es gibt verschiedene Möglichkeiten, wie wir Punkte in Julia darstellen könnten:\n", + " - Wir könnten die Koordinaten separat in zwei Variablen, x und y, speichern.\n", + " - Wir könnten die Koordinaten als Elemente in einem Tupel speichern.\n", + " - Wir könnten einen neuen Typ erstellen, um Punkte als Objekte darzustellen.\n", + "\n", + "Hier werden wir die dritte Option untersuchen." + ] + }, + { + "cell_type": "markdown", + "id": "270c430a-4157-4e54-bb27-660c4028e5c6", + "metadata": {}, + "source": [ + "Ein vom Programmierer definierter zusammengesetzter Typ wird auch als Struktur (engl. struct) bezeichnet. Die Strukturdefinition für einen Punkt sieht so aus:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c2e3f646-2d82-46a4-a265-01b919412c6d", + "metadata": {}, + "outputs": [], + "source": [ + "struct Point\n", + " x::Real\n", + " y::Real\n", + "end" + ] + }, + { + "cell_type": "markdown", + "id": "6b99219f-70ba-41a7-8c52-e3803a360087", + "metadata": {}, + "source": [ + "Die Kopfzeile zeigt an, dass die neue Struktur Point genannt wird. Der Körper definiert die Attribute oder Felder der Struktur. Die Point-Struktur hat zwei Felder: x und y.\n", + "\n", + "Eine Struktur ist wie eine Fabrik zur Erzeugung von Objekten. Um einen Punkt zu erstellen, rufst du Point auf, als wäre es eine Funktion, und übergibst die Werte der Felder als Argumente. Wenn Point als Funktion verwendet wird, wird dies Konstruktor genannt. Der Konstruktor gibt eine Instanz des Objekts zurück.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "197339a2-0d8b-4882-bab2-80ba56410f21", + "metadata": {}, + "outputs": [], + "source": [ + "p = Point(3.0, 4.0)\n", + "@show p;" + ] + }, + { + "cell_type": "markdown", + "id": "e35cbbf5-491e-44ff-b2c0-0cf6a8853083", + "metadata": {}, + "source": [ + "Die Typangabe (`::Real`) ist optional, kann aber hilfreich sein, um die korrekte Verwendung der Struktur zu erzwingen." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "849f1460-d228-4b22-a797-1077d75d1a2d", + "metadata": {}, + "outputs": [], + "source": [ + "p = Point(\"a\", 4.0)" + ] + }, + { + "cell_type": "markdown", + "id": "b86615f4-592f-41f7-b9d1-f5d1573cfd86", + "metadata": {}, + "source": [ + "Die Werte der Felder können mithilfe des `.` Operators abgerufen werden." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "00d090e4-d74d-4fad-ae8b-369c1046e48b", + "metadata": {}, + "outputs": [], + "source": [ + "@show p.x p.y;\n", + "@show distance = sqrt(p.x^2 + p.y^2);" + ] + }, + { + "cell_type": "markdown", + "id": "7c6baa9c-56e2-4595-9e6b-c798d9cea002", + "metadata": {}, + "source": [ + "Die Werte der Felder können mithilfe des `.` Operators abgerufen werden." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "91bd6248-a358-43e3-90cc-6b8398445aaf", + "metadata": {}, + "outputs": [], + "source": [ + "p.x = 2" + ] + }, + { + "cell_type": "markdown", + "id": "48b46edb-b8fd-46ca-a2ec-4aa0acbf6c01", + "metadata": {}, + "source": [ + "Wenn erforderlich, können veränderbare zusammengesetzte Typen mit dem Schlüsselwort `mutable struct` deklariert werden. Hier ist die Definition eines veränderbaren Punkts:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "804c2c32-7a84-4261-88d8-1bad6ba5e18c", + "metadata": {}, + "outputs": [], + "source": [ + "mutable struct MPoint\n", + " x::Real\n", + " y::Real\n", + "end\n", + "p = MPoint(3.0, 4.0)\n", + "p.x = 2.0\n", + "@show p;" + ] + }, + { + "cell_type": "markdown", + "id": "06f44f63-bf8e-45f5-9495-006e21fc7560", + "metadata": {}, + "source": [ + "Eine dritte Option ist es, einige Felder einer unveränderlichen Struktur als veränderbar zu definieren. Zum Beispiel kann eine Zuordnungstabellen innerhalb einer unveränderlichen Struktur geändert werden." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "62cab9ae-5e58-401c-bc93-17720914e530", + "metadata": {}, + "outputs": [], + "source": [ + "struct Book\n", + " title::String\n", + " author::String\n", + " properties::Dict{String, Any}\n", + "end\n", + "\n", + "book = Book(\"Der Hobbit\", \"J.R.R. Tolkien\", Dict(\"available\" => false))\n", + "@show book\n", + "book.properties[\"available\"] = true\n", + "@show book;" + ] + }, + { + "cell_type": "markdown", + "id": "53aa5851-35c2-4dd0-a1e0-b5bc8e21b9f6", + "metadata": {}, + "source": [ + "Du kannst eine Instanz auf die übliche Weise als Argument übergeben. Zum Beispiel:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e6113221-0c03-484a-99e0-f7d4fab70f03", + "metadata": {}, + "outputs": [], + "source": [ + "function print_point(p)\n", + " println(\"($(p.x), $(p.y))\")\n", + "end\n", + "print_point(p)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d5c6fa9e-c31d-4aff-a3fd-db3449904519", + "metadata": {}, + "outputs": [], + "source": [ + "function print_book(book)\n", + " println(\"Title: $(book.title)\")\n", + " println(\"Author: $(book.author)\")\n", + " available = book.properties[\"available\"]\n", + " println(\"Available: $(available)\")\n", + "end\n", + "print_book(book)" + ] + }, + { + "cell_type": "markdown", + "id": "916562a2-3402-41bb-b15d-01333915df99", + "metadata": {}, + "source": [ + "Funktionen können Instanzen als Rückgabewerte zurückgeben." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9c57c9f7-c4fd-4263-a55f-62f123aaaa8a", + "metadata": {}, + "outputs": [], + "source": [ + "function find_center(point1, point2)\n", + " x = (point1.x + point2.x)/2.0\n", + " y = (point1.y + point2.y)/2.0\n", + " return Point(x, y)\n", + "end\n", + "\n", + "point1 = Point(0.0, 0.0)\n", + "point2 = Point(10.0, 10.0)\n", + "\n", + "@show find_center(point1, point2);" + ] + }, + { + "cell_type": "markdown", + "id": "4afa9ca0-e6cd-4713-8caa-689c9dfdee42", + "metadata": {}, + "source": [ + "### Übung\n", + "\n", + " - Schreibe eine Funktion namens `point_distance`, die zwei Punkte als Argumente entgegennimmt und die euklidische Distanz zwischen ihnen zurückgibt." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b5957a05-e396-41c3-9b8f-f14f089115ab", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "id": "eecb6161-768e-4ae6-a600-d892894f8824", + "metadata": {}, + "source": [ + "### Referenzen und Werte\n", + "\n", + "Jedes Objekt (Instanz einer Struktur) wird an einer bestimmten Speicheradresse gespeichert. Der Operator `===` überprüft, ob zwei Variablen auf die gleiche Speicheradresse des Objekts zeigen. Zum Beispiel" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ed713d91-17f4-4010-a7d3-d39826cffc97", + "metadata": {}, + "outputs": [], + "source": [ + "book_copy = book\n", + "@show book_copy === book;" + ] + }, + { + "cell_type": "markdown", + "id": "582e0ac0-2304-429e-a678-c37ab157d5d6", + "metadata": {}, + "source": [ + "Das bedeutet, dass jede Änderung, die an `book_copy` vorgenommen wird, auch `book` modifiziert." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a9c46bac-d234-4616-a604-63bdf03b1393", + "metadata": {}, + "outputs": [], + "source": [ + "book.properties[\"available\"] = true\n", + "book_copy.properties[\"available\"] = false\n", + "\n", + "@show book;" + ] + }, + { + "cell_type": "markdown", + "id": "79339467-8994-4a5c-8987-3420d14cb290", + "metadata": {}, + "source": [ + "Wenn ein neues, eindeutiges Objekt benötigt wird (mit anderen Worten, eine Kopie nach Wert), können wir die Funktion `deepcopy` verwenden." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c36d23c8-2292-4568-aef4-7416c6f3e538", + "metadata": {}, + "outputs": [], + "source": [ + "book_copy = deepcopy(book)\n", + "@show book_copy === book;" + ] + }, + { + "cell_type": "markdown", + "id": "4cc4c096-d856-4d43-8808-94edcd3ad906", + "metadata": {}, + "source": [ + "Schließlich entspricht der `==` Operator zwischen Strukturen standardmäßig dem `===` Operator, da Julia nicht weiß, wie benutzerdefinierte Strukturen verglichen werden sollen. Es ist jedoch immer möglich, den `==` Operator für unsere benutzerdefinierten Typen neu zu implementieren." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3372eb89-cde6-4040-aa51-b4e76af97851", + "metadata": {}, + "outputs": [], + "source": [ + "import Base: ==\n", + "\n", + "function ==(book1::Book, book2::Book)\n", + " return book1.title == book2.title && book1.author == book2.author\n", + "end\n", + "\n", + "@show book_copy == book;\n", + "@show book_copy === book;" + ] + }, + { + "cell_type": "markdown", + "id": "02b533ba-2325-488a-838b-94cdf5ca25bb", + "metadata": {}, + "source": [ + "Damit können wir vergleichen, ob zwei Bücher gleich sind, auch wenn es sich um zwei unterschiedliche Instanzen desselben Typs handelt." + ] + }, + { + "cell_type": "markdown", + "id": "4e457ee2-813a-42a8-8ee0-600bb4b50812", + "metadata": {}, + "source": [ + "## Reine und unreine Funktionen" + ] + }, + { + "cell_type": "markdown", + "id": "fb008ae0-a457-45db-8f77-425d56e95b30", + "metadata": {}, + "source": [ + "Wir haben gesehen, dass es ziemlich praktisch ist, Objekte an Funktionen zu übergeben. Bisher haben wir Funktionen gesehen, die den Inhalt ausgeben oder ein neues Objekt erstellen. Keine dieser Funktionen ändert den Inhalt der Eingabeobjekte.\n", + " - Eine Funktion, die die Eingabe nicht ändert, wird auch als **rein** bezeichnet.\n", + " - Eine Funktion, die die Eingabe ändert, wird als **unrein** bezeichnet. In Julia werden unreine Funktionen durch Hinzufügen eines `!` als letztem Zeichen des Namens hervorgehoben.\n", + "\n", + "Betrachten wir eine modifizierte Version des Buchs als Beispiel." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7f892e07-a601-4cba-b58d-40be9c8e93ab", + "metadata": {}, + "outputs": [], + "source": [ + "book = Book(\"Der Hobbit\", \"J.R.R. Tolkien\", Dict(\"available\" => true, \"copies_in_stock\" => 10))\n", + "@show book;" + ] + }, + { + "cell_type": "markdown", + "id": "7dac83b5-1086-4ca9-9b36-827497825be6", + "metadata": {}, + "source": [ + "Dann könnten wir über eine Funktion nachdenken, die die Datenbank aktualisiert, wenn wir neue Exemplare bestellen." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "04937488-a556-44ad-97be-98b017f293fd", + "metadata": {}, + "outputs": [], + "source": [ + "function order_book!(book, number_of_copies)\n", + " if number_of_copies <= 0\n", + " return\n", + " end\n", + " book.properties[\"copies_in_stock\"] += number_of_copies\n", + " book.properties[\"available\"] = true\n", + "end\n", + "\n", + "order_book!(book, 5)\n", + "@show book;" + ] + }, + { + "cell_type": "markdown", + "id": "93bc2e46-8530-4d1e-b7fa-55a74d1831c8", + "metadata": {}, + "source": [ + "### Übung\n", + " - Schreibe eine unreine Funktion `sell_book!`, um das Buchobjekt zu aktualisieren, wenn wir ein Exemplar verkaufen. Die Funktion sollte eine Meldung ausgeben, wenn keine Exemplare verfügbar sind." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6e79fe95-767d-4b3e-af58-623db6dc0712", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "id": "d5bb0b58-e85e-4edb-80b6-19d2c7d49ac3", + "metadata": {}, + "source": [ + "## Weitere Übungen" + ] + }, + { + "cell_type": "markdown", + "id": "15fd6da2-f862-40ef-a58d-5e7be488565f", + "metadata": {}, + "source": [ + "- Erstelle eine Zeitstruktur, die die Uhrzeit des Tages (Stunde, Minute und Sekunde) speichert. Schreibe eine Funktion, die als Eingabe das Zeitobjekt nimmt und es ausgibt. Schreibe dann eine Funktion, die zwei Zeitobjekte zusammenzählt und ein neues Zeitobjekt zurückgibt. Wenn die Summe mehr als 24 Stunden beträgt, sollte sie wie am nächsten Tag zurückgesetzt werden." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5335e035-62ee-4d0f-acfc-a9e24ac26d99", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "id": "2e0fde12-1214-4709-a7cb-5ebfaa0af17a", + "metadata": {}, + "source": [ + "- Erstelle eine benutzerdefinierte Version der `==` Funktion, die überprüft, ob zwei Zeitobjekte identisch sind." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "966d4db1-c95a-4531-8209-a869519599ea", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "id": "4e8c3c1e-14fb-439f-97c7-076196f7e5b4", + "metadata": {}, + "source": [ + "- Erstelle eine benutzerdefinierte Version der `<` und `<=` Funktionen für Zeitobjekte." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c9b76667-731b-4ec2-aaf4-e94496f65b1a", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "id": "b79aad8c-647e-46d0-9b04-6a77cd219953", + "metadata": {}, + "source": [ + "- Erstelle eine benutzerdefinierte Version der `>` und `>=` Funktionen für Zeitobjekte." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7df56050-686e-4a87-aa86-9b7f61315aa2", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Julia 1.9.3", + "language": "julia", + "name": "julia-1.9" + }, + "language_info": { + "file_extension": ".jl", + "mimetype": "application/julia", + "name": "julia" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/2_Advanced_Data_Types_en.ipynb b/2_Advanced_Data_Types_en.ipynb new file mode 100644 index 0000000000000000000000000000000000000000..5161c0bc3096d70a32d7e34f9e15dea5e2247708 --- /dev/null +++ b/2_Advanced_Data_Types_en.ipynb @@ -0,0 +1,1141 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "4fe99eff-729a-4d93-ab82-487e5143bae5", + "metadata": {}, + "source": [ + "# Advanced Data Types" + ] + }, + { + "cell_type": "markdown", + "id": "7969b8f9-335a-4bd2-82f7-1d9795234ed5", + "metadata": {}, + "source": [ + "## Dictionaries" + ] + }, + { + "cell_type": "markdown", + "id": "ea8518c1-8e1d-4532-8055-e04c3aa3e7c4", + "metadata": {}, + "source": [ + "A dictionary contains a collection of indices, which are called keys, and a collection of values. Each key is associated with a single value. The association of a key and a value is called a key-value pair or sometimes an item.\n", + "\n", + "The function `Dict` creates a new dictionary with no items. Because `Dict` is the name of a built-in function, you should avoid using it as a variable name. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "59ae8d17-a6f6-4210-95bc-0e7492bc8a7a", + "metadata": {}, + "outputs": [], + "source": [ + "eng2de = Dict()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "28490ea3-c4d3-4e4d-915f-612ad36c9472", + "metadata": {}, + "outputs": [], + "source": [ + "eng2de[\"one\"] = \"ein\";" + ] + }, + { + "cell_type": "markdown", + "id": "f2aff40c-6dcb-421a-b67f-1662c5bf4702", + "metadata": {}, + "source": [ + "You can also initialize a dictionary with items as:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "92fc203b-4ba8-432a-a541-c4ccf3292195", + "metadata": {}, + "outputs": [], + "source": [ + "eng2de = Dict(\"one\" => \"ein\", \"two\" => \"zwei\", \"three\" => \"drei\")" + ] + }, + { + "cell_type": "markdown", + "id": "c52d24af-ec90-4b8c-bdd9-988129a7fa81", + "metadata": {}, + "source": [ + "Dictionaries are mutable, meaning that it is always possible to modify their elements, add new key-value pairs or removing existing ones." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "22b295dc-994e-4bbc-ac8d-da5ab9e73493", + "metadata": {}, + "outputs": [], + "source": [ + "eng2de[\"four\"] = \"VIER\"\n", + "@show eng2de\n", + "eng2de[\"four\"] = \"vier\"\n", + "@show eng2de\n", + "delete!(eng2de, \"four\")\n", + "@show eng2de;" + ] + }, + { + "cell_type": "markdown", + "id": "01513ad2-3083-4c89-adca-ccc8a88d93d4", + "metadata": {}, + "source": [ + "In general, the order of the key-value pairs is unpredictable. However this is not important, as the values are always accessed using the keys." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e9e4c5b9-9539-4294-a6ec-0a29fb76bf7b", + "metadata": {}, + "outputs": [], + "source": [ + "eng2de[\"two\"]" + ] + }, + { + "cell_type": "markdown", + "id": "9944dbbd-478b-4ae1-ac89-e16be08a0868", + "metadata": {}, + "source": [ + "If the key isn’t in the dictionary, you get an exception:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8221269b-7a8f-4cfd-ab8e-0aa4fd6c962d", + "metadata": {}, + "outputs": [], + "source": [ + "eng2de[\"four\"]" + ] + }, + { + "cell_type": "markdown", + "id": "a545abaa-78dc-4625-84e9-03b1c8beaaf8", + "metadata": {}, + "source": [ + "The `length` function works on dictionaries; it returns the number of key-value pairs:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0e242667-b921-4242-bdcc-cbcac14909b2", + "metadata": {}, + "outputs": [], + "source": [ + "length(eng2de)" + ] + }, + { + "cell_type": "markdown", + "id": "8e42655b-f2a0-41f0-be90-015ebfeafdb9", + "metadata": {}, + "source": [ + "The function `keys` returns a collection with the keys of the dictionary:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3236f973-d3fa-42ba-a1c0-41e0002446cb", + "metadata": {}, + "outputs": [], + "source": [ + "keys(eng2de)" + ] + }, + { + "cell_type": "markdown", + "id": "acfa7044-5695-4af8-b4bc-320c8a48a220", + "metadata": {}, + "source": [ + "Now you can use the `∈` operator to see whether something appears as a key in the dictionary:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1fdeb10c-0d84-4c22-b734-d68e2eafe375", + "metadata": {}, + "outputs": [], + "source": [ + "@show \"one\" ∈ keys(eng2de)\n", + "@show \"four\" ∈ keys(eng2de);" + ] + }, + { + "cell_type": "markdown", + "id": "986919d6-4f27-4fad-b222-20697bf6af40", + "metadata": {}, + "source": [ + "To see whether something appears as a value in a dictionary, you can use the function `values`, which returns a collection of values, and then use the `∈` operator:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ab90dad1-61d0-4dbd-b829-a354c13fcb71", + "metadata": {}, + "outputs": [], + "source": [ + "@show \"ein\" ∈ values(eng2de)\n", + "@show \"vier\" ∈ values(eng2de);" + ] + }, + { + "cell_type": "markdown", + "id": "049c9dfd-1e51-4898-98e5-a4b812d0bba2", + "metadata": {}, + "source": [ + "### Loops over dictionaries\n", + "\n", + "You can traverse the keys of the dictionary in a `for` statement." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e7062d3f-2125-4ecd-ab13-d04944a71fe1", + "metadata": {}, + "outputs": [], + "source": [ + "function print_dictionary(dic)\n", + " for key in keys(dic)\n", + " println(key, \" \", dic[key])\n", + " end\n", + "end\n", + "\n", + "print_dictionary(eng2de)" + ] + }, + { + "cell_type": "markdown", + "id": "cf27195c-e601-49ca-b03d-63162bf59bce", + "metadata": {}, + "source": [ + "Again, the keys are in no particular order. To traverse the keys in alphabetically sorted order, you can combine `sort` and `collect`:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6d52aeba-3c7e-405c-bcfe-d76e37e94f51", + "metadata": {}, + "outputs": [], + "source": [ + "function print_dictionary_sorted(dic)\n", + " for key in sort(collect(keys(dic)))\n", + " println(key, \" \", dic[key])\n", + " end\n", + "end\n", + "\n", + "print_dictionary_sorted(eng2de)" + ] + }, + { + "cell_type": "markdown", + "id": "8daa9d3e-19de-4415-ba6c-6aeb174b38fa", + "metadata": {}, + "source": [ + "### Exercise\n", + " - Write a function that given a string as input counts how many times each letter appears. Use a dictionary." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "aba1978b-e675-48a7-89aa-75553db70537", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "id": "3a9b281f-6cc0-4d39-b9e2-d816823f9873", + "metadata": {}, + "source": [ + "## Tuples and named tuples" + ] + }, + { + "cell_type": "markdown", + "id": "a722109e-86cc-44e3-9256-a3e93a1668f5", + "metadata": {}, + "source": [ + "A tuple is a sequence of values. The values can be of any type, and they are indexed by integers. The tuples are immutable and each element can have its own type." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8502cf2e-8bea-4707-811c-f4e6e1de3c8f", + "metadata": {}, + "outputs": [], + "source": [ + "t = 'a', 'b', 'c', 'd', 'e'" + ] + }, + { + "cell_type": "markdown", + "id": "d01f5647-a240-4620-9a3a-782835aca39c", + "metadata": {}, + "source": [ + "Although it is not necessary, it is common to enclose tuples in parentheses:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bfa31b99-bf9d-49bb-babc-fe8a65248429", + "metadata": {}, + "outputs": [], + "source": [ + "t = ('a', 'b', 'c', 'd', 'e')" + ] + }, + { + "cell_type": "markdown", + "id": "3fa935e0-0611-4b8a-982c-329c33a74f99", + "metadata": {}, + "source": [ + "To create a tuple with a single element, you have to include a final comma:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cb1bea15-2b80-43b2-be8e-27507d550fca", + "metadata": {}, + "outputs": [], + "source": [ + "t1 = ('a',)\n", + "@show typeof(t1)\n", + "\n", + "t2 = ('a')\n", + "@show typeof(t2);" + ] + }, + { + "cell_type": "markdown", + "id": "193457ac-4e4b-4e58-8c28-6d8b4331d532", + "metadata": {}, + "source": [ + "Another way to create a tuple is the built-in function tuple. With no argument, it creates an empty tuple:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "952acafe-ca5d-4b58-8969-224b0fe3a28f", + "metadata": {}, + "outputs": [], + "source": [ + "t3 = tuple()\n", + "@show typeof(t3)\n", + "\n", + "t4 = tuple(1, 'a', π, 12.0)\n", + "@show typeof(t4);" + ] + }, + { + "cell_type": "markdown", + "id": "729c3597-1a35-4a26-ae7a-6dadee31daeb", + "metadata": {}, + "source": [ + "Using the bracket operator it is possible to access an element. Note, differently from other programming languages (for example C, C++, Python) in Julia the first element is 1." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9817c28f-428d-4d5b-8384-608f9b4d763d", + "metadata": {}, + "outputs": [], + "source": [ + "t4[2]" + ] + }, + { + "cell_type": "markdown", + "id": "2519be57-8c10-4878-a772-017b099f6a4c", + "metadata": {}, + "source": [ + "It is also possible to get multiple elements by using slices." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c48ac07f-3a4e-4bb8-9551-2973ea8d2f9c", + "metadata": {}, + "outputs": [], + "source": [ + "@show t4[1:3];" + ] + }, + { + "cell_type": "markdown", + "id": "aeda8602-f9da-4173-a692-54e2e9a0e178", + "metadata": {}, + "source": [ + "But if you try to modify one of the elements of the tuple, you get an error:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cfc94cc9-832c-45d2-85b8-aaf789f33f6a", + "metadata": {}, + "outputs": [], + "source": [ + "t4[2] = 'b'" + ] + }, + { + "cell_type": "markdown", + "id": "b9f13b5c-9e61-46b9-a47d-f90199bd7bd2", + "metadata": {}, + "source": [ + "Because tuples are immutable, you can’t modify the elements." + ] + }, + { + "cell_type": "markdown", + "id": "a10cb9a7-8f44-44f8-831f-178b780e4ac9", + "metadata": {}, + "source": [ + "Strictly speaking, a function can only return one value, but if the value is a tuple, the effect is the same as returning multiple values. For example, if you want to divide two integers and compute the quotient and remainder, it is inefficient to compute x ÷ y and then x % y. It is better to compute them both at the same time.\n", + "\n", + "The built-in function `divrem` takes two arguments and returns a tuple of two values, the quotient and remainder. You can store the result as a tuple: " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d1dde137-036f-4b93-8010-13b3e835ebd8", + "metadata": {}, + "outputs": [], + "source": [ + "t = divrem(7, 3)" + ] + }, + { + "cell_type": "markdown", + "id": "ea615dbd-effb-4442-b160-20e7c9b6c22e", + "metadata": {}, + "source": [ + "Alternatively, we can use tuple assignment to store the elements separately:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c4969556-7945-43c9-8b96-1ea1032cbb3c", + "metadata": {}, + "outputs": [], + "source": [ + "q, r = divrem(7, 3)\n", + "\n", + "@show q r;" + ] + }, + { + "cell_type": "markdown", + "id": "4574e191-aaa8-4834-8837-54947d6ddf30", + "metadata": {}, + "source": [ + "### Gather and scatter\n", + "\n", + "Functions can take a variable number of arguments. A parameter name that ends with `...` gathers arguments into a tuple. For example, `printall` takes any number of arguments and prints them one by line:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "43f8c7ad-5ac2-425e-a50f-c45624bb3d8a", + "metadata": {}, + "outputs": [], + "source": [ + "function printall(args...)\n", + " for arg in args\n", + " println(arg)\n", + " end\n", + "end\n", + "\n", + "printall(1)\n", + "printall(1, 2.0, '3')" + ] + }, + { + "cell_type": "markdown", + "id": "eb662374-fe83-49d7-a5be-d9582d037ad1", + "metadata": {}, + "source": [ + "The complement of gather is scatter. If you have a sequence of values and you want to pass it to a function as multiple arguments, you can use the `...` operator. For example, `divrem` takes exactly two arguments; it doesn’t work with a tuple:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bf55fc10-8432-41e3-bd6c-2244c8c96513", + "metadata": {}, + "outputs": [], + "source": [ + "t = (7, 3)\n", + "divrem(t)" + ] + }, + { + "cell_type": "markdown", + "id": "d05def39-3244-4acd-a082-a7ee532f8f1d", + "metadata": {}, + "source": [ + "But if you scatter the tuple, it works:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e7df53bc-6b2d-4501-9ca8-61e3cb79eb1a", + "metadata": {}, + "outputs": [], + "source": [ + "t = (7, 3)\n", + "divrem(t...)" + ] + }, + { + "cell_type": "markdown", + "id": "2cf01c32-9d1b-4e83-9375-f737e51c58ed", + "metadata": {}, + "source": [ + "### Dictionaries and Tuples" + ] + }, + { + "cell_type": "markdown", + "id": "00e97ccc-8e64-4eef-84be-85a266eb3490", + "metadata": {}, + "source": [ + "Dictionaries can be used as iterators that iterate the key-value pairs. You can use it in a `for` loop like this:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ed483334-36d0-4700-b178-cd9dc5f12189", + "metadata": {}, + "outputs": [], + "source": [ + "d = Dict('a'=>1, 'b'=>2, 'c'=>3);\n", + "for (key, value) in d\n", + " println(key, \" \", value)\n", + "end" + ] + }, + { + "cell_type": "markdown", + "id": "dcb05236-810a-410b-aaa0-0cb431e3e64f", + "metadata": {}, + "source": [ + "It is common to use tuples as keys in dictionaries. For example, a telephone directory might map from last-name, first-name pairs to telephone numbers. Assuming that we have defined last, first and number, we could write:" + ] + }, + { + "cell_type": "markdown", + "id": "e5462d35-fa68-42d8-ba00-c5dd1747c557", + "metadata": {}, + "source": [ + "`directory[last, first] = number`" + ] + }, + { + "cell_type": "markdown", + "id": "9980d710-392b-4716-b44d-98e6c5c8b838", + "metadata": {}, + "source": [ + "### Named tuples" + ] + }, + { + "cell_type": "markdown", + "id": "e514c4bd-c17c-44f4-a89f-88154cc1bf6c", + "metadata": {}, + "source": [ + "Named tuples are a special type of tuple in Julia where each element has a specific name associated with it. This allows you to access elements by their names, making the code more readable and self-explanatory." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "78fb5959-407a-4128-9287-bb9d455f22dc", + "metadata": {}, + "outputs": [], + "source": [ + "person = (name = \"Michele\", age = 28, city = \"Stuttgart\")" + ] + }, + { + "cell_type": "markdown", + "id": "63075b2d-ef86-48e4-8f84-981f81fdece0", + "metadata": {}, + "source": [ + "Named tuples are immutable, however it is possible to update the content, or to add new elements, by creating a new version. For example:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ecd22e07-5ba3-4f11-bc77-d967a6fc3fe8", + "metadata": {}, + "outputs": [], + "source": [ + "updated_person = (person..., age = 29)\n", + "updated_person = (person..., number = \"0711 ...\")" + ] + }, + { + "cell_type": "markdown", + "id": "347fe4ea-5b63-4fb8-91bc-2b7b8a0c6a30", + "metadata": {}, + "source": [ + "### Exercise\n", + " - Write a function `swap_first_last` that takes a tuple and returns a new tuple with the first and last elements swapped. Tip: use a combination of the `...` operator and of this slice `[2:end-1]`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3721b654-b182-426d-b799-a69e0b53a550", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "id": "647530cd-480a-414f-a8ec-1375e05a9e1b", + "metadata": {}, + "source": [ + "## Objects and structs" + ] + }, + { + "cell_type": "markdown", + "id": "00b9bdb1-86ad-47f6-b8c3-88e85878eaff", + "metadata": {}, + "source": [ + "At this point you know how to use functions to organize code and built-in types to organize data. The next step is to learn how to build your own types to organize both code and data.\n", + "\n", + "We have used many of Julia’s built-in types; now we are going to define a new type. As an example, we will create a type called Point that represents a point in two-dimensional space.\n", + " \n", + "There are several ways we might represent points in Julia:\n", + " - We could store the coordinates separately in two variables, x and y.\n", + " - We could store the coordinates as elements in an tuple.\n", + " - We could create a new type to represent points as objects.\n", + "\n", + "Here we will investigate the third option." + ] + }, + { + "cell_type": "markdown", + "id": "9aa53d46-033b-4559-a5d8-e95357a257a5", + "metadata": {}, + "source": [ + "A programmer-defined composite type is also called a struct. The struct definition for a point looks like this:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c2e3f646-2d82-46a4-a265-01b919412c6d", + "metadata": {}, + "outputs": [], + "source": [ + "struct Point\n", + " x::Real\n", + " y::Real\n", + "end" + ] + }, + { + "cell_type": "markdown", + "id": "fb9be134-9730-4dbd-9e05-51dd94e9d8e0", + "metadata": {}, + "source": [ + "The header indicates that the new struct is called Point. The body defines the attributes or fields of the struct. The Point struct has two fields: x and y.\n", + "\n", + "A struct is like a factory for creating objects. To create a point, you call Point as if it were a function having as arguments the values of the fields. When Point is used as a function, it is called a constructor. The constructor returns an instance of the object." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "197339a2-0d8b-4882-bab2-80ba56410f21", + "metadata": {}, + "outputs": [], + "source": [ + "p = Point(3.0, 4.0)\n", + "@show p;" + ] + }, + { + "cell_type": "markdown", + "id": "b0134aa7-f356-4d71-9d46-959bd3cfe89a", + "metadata": {}, + "source": [ + "The type speficication (`::Real`) is optional, but can be helpful to enforce correct usage of the struct." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "849f1460-d228-4b22-a797-1077d75d1a2d", + "metadata": {}, + "outputs": [], + "source": [ + "p = Point(\"a\", 4.0)" + ] + }, + { + "cell_type": "markdown", + "id": "e3011b23-816d-4aa2-be61-7eb8f4aee9d1", + "metadata": {}, + "source": [ + "The values of the fields can be accessed using the `.` operator." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "00d090e4-d74d-4fad-ae8b-369c1046e48b", + "metadata": {}, + "outputs": [], + "source": [ + "@show p.x p.y;\n", + "@show distance = sqrt(p.x^2 + p.y^2);" + ] + }, + { + "cell_type": "markdown", + "id": "08748a8c-f76c-4f14-b3d2-9db99fb28e87", + "metadata": {}, + "source": [ + "Structs are however by default immutable, after construction the fields can not change value:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "91bd6248-a358-43e3-90cc-6b8398445aaf", + "metadata": {}, + "outputs": [], + "source": [ + "p.x = 2" + ] + }, + { + "cell_type": "markdown", + "id": "629c1004-5d0f-4093-b546-473c94c91b44", + "metadata": {}, + "source": [ + "Where required, mutable composite types can be declared with the keyword mutable struct. Here is the definition of a mutable point:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "804c2c32-7a84-4261-88d8-1bad6ba5e18c", + "metadata": {}, + "outputs": [], + "source": [ + "mutable struct MPoint\n", + " x::Real\n", + " y::Real\n", + "end\n", + "p = MPoint(3.0, 4.0)\n", + "p.x = 2.0\n", + "@show p;" + ] + }, + { + "cell_type": "markdown", + "id": "1bd558dd-e6c3-4dc0-9476-768c59178708", + "metadata": {}, + "source": [ + "A third option is to let some fields of an unmutable struct to be mutable. For example a dictionary inside an unmutable struct can be modified." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "62cab9ae-5e58-401c-bc93-17720914e530", + "metadata": {}, + "outputs": [], + "source": [ + "struct Book\n", + " title::String\n", + " author::String\n", + " properties::Dict{String, Any}\n", + "end\n", + "\n", + "book = Book(\"Der Hobbit\", \"J.R.R. Tolkien\", Dict(\"available\" => false))\n", + "@show book\n", + "book.properties[\"available\"] = true\n", + "@show book;" + ] + }, + { + "cell_type": "markdown", + "id": "31e2098b-5079-4cb5-bf64-a7a78754af32", + "metadata": {}, + "source": [ + "You can pass an instance as an argument in the usual way. For example:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e6113221-0c03-484a-99e0-f7d4fab70f03", + "metadata": {}, + "outputs": [], + "source": [ + "function print_point(p)\n", + " println(\"($(p.x), $(p.y))\")\n", + "end\n", + "print_point(p)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d5c6fa9e-c31d-4aff-a3fd-db3449904519", + "metadata": {}, + "outputs": [], + "source": [ + "function print_book(book)\n", + " println(\"Title: $(book.title)\")\n", + " println(\"Author: $(book.author)\")\n", + " available = book.properties[\"available\"]\n", + " println(\"Available: $(available)\")\n", + "end\n", + "print_book(book)" + ] + }, + { + "cell_type": "markdown", + "id": "3b12a004-81d9-4bbc-9e2e-d2c281dcbe18", + "metadata": {}, + "source": [ + "Functions can return instances as return values." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9c57c9f7-c4fd-4263-a55f-62f123aaaa8a", + "metadata": {}, + "outputs": [], + "source": [ + "function find_center(point1, point2)\n", + " x = (point1.x + point2.x)/2.0\n", + " y = (point1.y + point2.y)/2.0\n", + " return Point(x, y)\n", + "end\n", + "\n", + "point1 = Point(0.0, 0.0)\n", + "point2 = Point(10.0, 10.0)\n", + "\n", + "@show find_center(point1, point2);" + ] + }, + { + "cell_type": "markdown", + "id": "078b31ab-11e1-4596-8271-f0d33418eab8", + "metadata": {}, + "source": [ + "### Exercise\n", + "\n", + " - Write a function called `point_distance` which takes two points as arguments and returns the Euclidean distance between them." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b5957a05-e396-41c3-9b8f-f14f089115ab", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "0fb1f6bc-e6e5-4897-bbb6-880e40e3bf20", + "metadata": {}, + "source": [ + "### References and values\n", + "\n", + "Each object (instance of a struct) is stored at some memory address. The operator `===` checks if two variables point to the same memory address of the object. For example" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ed713d91-17f4-4010-a7d3-d39826cffc97", + "metadata": {}, + "outputs": [], + "source": [ + "book_copy = book\n", + "@show book_copy === book;" + ] + }, + { + "cell_type": "markdown", + "id": "636b6713-f4ed-4220-a159-2918bd44f78e", + "metadata": {}, + "source": [ + "This means that any change made to `book_copy` will also modify `book`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a9c46bac-d234-4616-a604-63bdf03b1393", + "metadata": {}, + "outputs": [], + "source": [ + "book.properties[\"available\"] = true\n", + "book_copy.properties[\"available\"] = false\n", + "\n", + "@show book;" + ] + }, + { + "cell_type": "markdown", + "id": "6bcbf983-40fa-4fc8-8eca-7cd7c45778dc", + "metadata": {}, + "source": [ + "If a new, distinct, object is needed (in other words, a copy by value), we can use the function `deepcopy`. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c36d23c8-2292-4568-aef4-7416c6f3e538", + "metadata": {}, + "outputs": [], + "source": [ + "book_copy = deepcopy(book)\n", + "@show book_copy === book;" + ] + }, + { + "cell_type": "markdown", + "id": "02cc3ec7-e712-4c4b-abf5-9bfc98e68a91", + "metadata": {}, + "source": [ + "Finally, the `==` operator between structs defaults to the `===` operator as Julia has no way of knowing how to compare custom structs. However, it is always possible to reimplement the `==` operator for our custom types." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3372eb89-cde6-4040-aa51-b4e76af97851", + "metadata": {}, + "outputs": [], + "source": [ + "import Base: ==\n", + "\n", + "function ==(book1::Book, book2::Book)\n", + " return book1.title == book2.title && book1.author == book2.author\n", + "end\n", + "\n", + "@show book_copy == book;\n", + "@show book_copy === book;" + ] + }, + { + "cell_type": "markdown", + "id": "87c1e4fb-d4e2-4ada-a97f-61273012146c", + "metadata": {}, + "source": [ + "With this we can compare if two books are the same, even if they are two distinct instances of the same struct." + ] + }, + { + "cell_type": "markdown", + "id": "9263a1ae-52ee-4afc-9d9f-0f1341b64bc0", + "metadata": {}, + "source": [ + "## Pure and impure functions" + ] + }, + { + "cell_type": "markdown", + "id": "f638e9b3-9926-46fc-81e0-d49c877a3bbb", + "metadata": {}, + "source": [ + "We have seen that it is quite convenient to pass objects to functions. So far we have seen functions that print the content or that create a new object. None of these functions are modifying the content of the input objects.\n", + " - A function that does not modify the input it is also said **pure**.\n", + " - A function which modifies the input it is said **impure**. In Julia impure functions are highlighted by adding a `!` as the last character of the name.\n", + "\n", + "Let's consider a modified version of the book for an example." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7f892e07-a601-4cba-b58d-40be9c8e93ab", + "metadata": {}, + "outputs": [], + "source": [ + "book = Book(\"Der Hobbit\", \"J.R.R. Tolkien\", Dict(\"available\" => true, \"copies_in_stock\" => 10))\n", + "@show book;" + ] + }, + { + "cell_type": "markdown", + "id": "99f4d6c9-2633-4394-b6a0-e0ce0c05e0db", + "metadata": {}, + "source": [ + "Then we could think of a function which updates the database whenever we order new copies." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "04937488-a556-44ad-97be-98b017f293fd", + "metadata": {}, + "outputs": [], + "source": [ + "function order_book!(book, number_of_copies)\n", + " if number_of_copies <= 0\n", + " return\n", + " end\n", + " book.properties[\"copies_in_stock\"] += number_of_copies\n", + " book.properties[\"available\"] = true\n", + "end\n", + "\n", + "order_book!(book, 5)\n", + "@show book;" + ] + }, + { + "cell_type": "markdown", + "id": "b30bd560-5ff3-4706-9f53-e6a5158651e9", + "metadata": {}, + "source": [ + "### Exercise\n", + " - Write an inpure function `sell_book!` for updating the book object whenever we sell a single copy. The function should complain if there are no copies available." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6e79fe95-767d-4b3e-af58-623db6dc0712", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "id": "5ed4d4e0-0454-4298-9a56-8fb32634aa24", + "metadata": {}, + "source": [ + "## Further exercises" + ] + }, + { + "cell_type": "markdown", + "id": "8446f1db-d40f-4311-9597-3b3b4d913151", + "metadata": {}, + "source": [ + "- Create a time struct which stores the time of the day (hour, minute and second). Write a function which takes as input the time object and prints it. Then write a function which sums together two time objects and returns a new time object. If the total is more than 24 hours, it should reset as if it was the next day." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5335e035-62ee-4d0f-acfc-a9e24ac26d99", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "id": "32844b6f-518a-4174-83c6-0d7ebeabe4e4", + "metadata": {}, + "source": [ + " - Create a custom version of the `==` function which checks if two time objects are the same." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "966d4db1-c95a-4531-8209-a869519599ea", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "id": "baa7e06f-e183-4ee7-912a-e22255e18e21", + "metadata": {}, + "source": [ + " - Create a custom version of the `<` and `<=` functions for time objects." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c9b76667-731b-4ec2-aaf4-e94496f65b1a", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "id": "1bdbd748-7482-4f54-99a7-3d6e74b65575", + "metadata": {}, + "source": [ + " - Create a custom version of the `>` and `>=` functions for time objects." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7df56050-686e-4a87-aa86-9b7f61315aa2", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Julia 1.9.3", + "language": "julia", + "name": "julia-1.9" + }, + "language_info": { + "file_extension": ".jl", + "mimetype": "application/julia", + "name": "julia" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/README.md b/README.md index 0bb394f680c7dc29a7e8cd6e205a6e9f45b7a5fa..d518e875a5566ab476d09bb92332790dc339f8cf 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,13 @@ # Julia-seminar -Material für den Julia-Seminar-Kurs. -Das Kursmaterial wurde aus zwei Quellen angepasst: +Das Kursmaterial für dieses Julia-Seminar wurde aus zwei Quellen angepasst: - der [Kurs](https://github.com/mfherbst/2022-rwth-julia-workshop.git) von Michael Herbst ([MIT Lizenz](https://opensource.org/licenses/mit/)). - das Buch [ThinkJulia](https://benlauwens.github.io/ThinkJulia.jl/latest/book.html) von Allen Downey und Ben Lauwens ([Creative Commons Namensnennung-Nicht-kommerziell 3.0 Unported Lizenz](https://creativecommons.org/licenses/by-nc/3.0/deed.de)). -Eine sehr umfangreiche Spickzettel findest du [hier](https://cheatsheet.juliadocs.org/). +Einen sehr umfangreichen Spickzettel findest du [hier](https://cheatsheet.juliadocs.org/). ## Software und Material -Der Kurs erfordert verschiedene Dinge: eine funktionierende Installation von [Julia 1.9](https://julialang.org/downloads/), [Jupyter](https://jupyter.org/), [IJulia.jl](https://github.com/JuliaLang/IJulia.jl), das Kursmaterial und verschiedene Abhängigkeiten. Um alles zu herunterzuladen und zu installieren, befolgst Du diese Schritte: +Der Kurs erfordert verschiedene Dinge: eine funktionierende Installation von [Julia 1.9](https://julialang.org/downloads/), [Jupyter](https://jupyter.org/), [IJulia.jl](https://github.com/JuliaLang/IJulia.jl), das Kursmaterial und verschiedene Abhängigkeiten. Um alles herunterzuladen und zu installieren, befolgst Du diese Schritte: ### 1) Julia herunterladen Um dem Kurs zu folgen, benötigst du **Julia 1.9**. @@ -26,28 +25,58 @@ Das [lädt das install.jl-Skript herunter](https://gitlab.mathematik.uni-stuttga ### 2) Alles andere (Experten-Version) -Als Alternative kannst Du auch die folgenden Befehle manuell ausführen (dies setzt voraus, dass `git` und `julia` von der Kommandozeile aus verfügbar sind): +Alternativ kannst Du auch die folgenden Befehle manuell ausführen (dies setzt voraus, dass `git` und `julia` von der Kommandozeile aus verfügbar sind): ``` git clone https://gitlab.mathematik.uni-stuttgart.de/stammbn/Julia-seminar/ cd Julia-seminar julia install-manual.jl ``` -### 3) Starten des Notebooks -Um das Notebook zu starten, stelle sicher, dass Du Dich im Ordner `Julia-seminar` befindest, und führe dann `julia` aus: Eine interaktive Julia-Befehlszeile wird geöffnet. Führe darin folgenden Befehl aus: +### 3) Das Notebook starten +#### Aus der Julia REPL + +Um das Notebook zu starten, stelle sicher, dass Du dich im Ordner `Julia-Seminar` befindest, und führe dann `julia` aus: Eine interaktive Julia-Befehlszeile wird geöffnet. Führe darin den folgenden Befehl aus: + +```julia +using Pkg +Pkg.activate(pwd()) +using IJulia +notebook(dir=pwd()) +``` + +und das Notebook wird automatisch in einem Browser geöffnet. +Navigiere zu den Dateien und öffne das Notebook Nummer 0. + +#### Über die Befehlszeile + +Alternativ kann man das Notebook auch über die Befehlszeile öffnen: + + +```bash +julia -L start_notebook.jl ``` -using IJulia; notebook(dir=pwd()) + +### \* Für Benutzer mit mehreren Julia-Versionen + +Für Benutzer mit mehreren Julia-Versionen, falls der entsprechende Kernel in Jupyter Notebook nicht gefunden werden kann, führe bitte `installkernel("julia", "--project=@.")` (nur einmal) aus, bevor Du `notebook(dir=pwd())` ausführst, um zuerst den Kernel zu installieren: + +```julia +using Pkg +Pkg.activate(pwd()) +using IJulia +installkernel("julia", "--project=@.") +notebook(dir=pwd()) ``` -und das Notebook wird automatisch im Browser geöffnet. + +Nun sollte man in Jupyter Notebook einen neuen Kernel finden, der mit der aktuellen Julia-Version verknüpft ist und den Namen `julia "Julia-Version"` trägt. ### Fehlerbehebung Wenn Du auf Probleme stößt, werfe einen Blick auf den [ausgezeichneten Problembehandlungsabschnitt](https://carstenbauer.github.io/WorkshopWizard.jl/dev/troubleshooting/) aus dem WorkshopWizard-Paket von Carsten Bauer (das von `install.jl` verwendet wird). # Julia-seminar -Material for the Julia seminar course. -The course material is adapted from two sources: +Material for the Julia seminar course which is adapted from two sources: - the [course](https://github.com/mfherbst/2022-rwth-julia-workshop.git) from Michael Herbst ([MIT license](https://opensource.org/license/mit/)). - the book [ThinkJulia](https://benlauwens.github.io/ThinkJulia.jl/latest/book.html) from Allen Downey and Ben Lauwens ([Creative Commons Attribution-NonCommercial 3.0 Unported license](https://creativecommons.org/licenses/by-nc/3.0/deed.en)). @@ -80,47 +109,44 @@ julia install-manual.jl ``` ### 3) Starting the notebook + +#### From Julia REPL + To start the notebook make sure to be in the folder `Julia-seminar` and then run `julia`: an interactive Julia command line will open. In there run this command +```julia +using Pkg +Pkg.activate(pwd()) +using IJulia +notebook(dir=pwd()) ``` -using IJulia; notebook(dir=pwd()) -``` -and the notebook will automatically open in a browser. +and the notebook will automatically open in a browser. Navigate the files and open notebook number 0. -### Troubleshooting -If you are facing issues, check out -the [great troubleshooting section](https://carstenbauer.github.io/WorkshopWizard.jl/dev/troubleshooting/) -from the WorkshopWizard package by Carsten Bauer (which is being used by `install.jl`). - -## For Developers: Setting Up `pre-commit` - -[`pre-commit`](https://pre-commit.com/) is a framework that helps to manage and maintain pre-commit hooks to ensure that your code adheres to a consistent style, prevents errors, and adheres to other quality assurance checks. - -1. **Install `pre-commit`:** - To ensure smooth development, install `pre-commit` using pip by running the following command: +#### From command line - ```bash - pip install pre-commit - ``` +Alternatively, one can open the notebook from the command line: - For more information and installation options, visit the [`pre-commit`](https://pre-commit.com/) website. - -2. **Navigate to the Project Directory:** - Change into the project directory, i.e., `julia-seminar` by running: +```bash +julia -L start_notebook.jl +``` - ```bash - cd julia-seminar - ``` +### \* For users with multiple Julia versions -3. **Install Hooks:** - Install the git hooks by executing: +For users with multiple Julia versions, if the corresponding kernel cannot be found in Jupyter Notebook, please run `installkernel("julia", "--project=@.")` (only once) before executing `notebook(dir=pwd())` to first install the kernel: - ```bash - pre-commit install - ``` +```julia +using Pkg +Pkg.activate(pwd()) +using IJulia +installkernel("julia", "--project=@.") +notebook(dir=pwd()) +``` - This command installs the pre-commit script alongside existing git hooks. +Now, one should find a new kernel related to the current Julia version, named `julia "Julia-version"`, in Jupyter Notebook. -Once the pre-commit hook is installed, it will automatically check your code for any issues before each commit. If the checks do not pass, you will be prompted to fix them before proceeding. +### Troubleshooting +If you are facing issues, check out +the [great troubleshooting section](https://carstenbauer.github.io/WorkshopWizard.jl/dev/troubleshooting/) +from the WorkshopWizard package by Carsten Bauer (which is being used by `install.jl`). diff --git a/0_Installation.ipynb b/src/0_Installation.ipynb similarity index 58% rename from 0_Installation.ipynb rename to src/0_Installation.ipynb index 15edf52b4e1428867ec036369da81edd7527b8b4..019d08094dc2b7c22bc1e8dfb6a5674721d9a463 100644 --- a/0_Installation.ipynb +++ b/src/0_Installation.ipynb @@ -5,7 +5,8 @@ "id": "16b28ead", "metadata": {}, "source": [ - "# Installation and Setup" + "# Installation and Setup\n", + "Please follow the steps 1-3 outlined in README.md to download and install Julia, and to open the notebook 0_Installation.ipynb in a Jupyter notebook. " ] }, { @@ -13,95 +14,8 @@ "id": "31ac33c0-18a9-4cfa-8e04-3ee1a0c909eb", "metadata": {}, "source": [ - "# Installation und Einrichtung" - ] - }, - { - "cell_type": "markdown", - "id": "8829affd", - "metadata": {}, - "source": [ - "## Software and material\n", - "The course requires various things: a working installation of [Julia 1.9](https://julialang.org/downloads/), [Jupyter](https://jupyter.org/), [IJulia.jl](https://github.com/JuliaLang/IJulia.jl), the course material and various dependencies. To get everything follow these steps:\n", - "\n", - "### 1) Getting Julia\n", - "For following the course you will need **Julia 1.9**.\n", - "Julia can be easily obtained in binary form from [Julia downloads](https://julialang.org/downloads/).\n", - "\n", - "### 2) Getting all the rest\n", - "\n", - "To get the remaining files and dependencies start up `julia` and in the resulting REPL shell, copy and paste the following:\n", - "```julia\n", - "import Downloads\n", - "script = Downloads.download(\"https://gitlab.mathematik.uni-stuttgart.de/stammbn/julia-seminar/-/raw/main/install.jl?ref_type=heads\")\n", - "include(script)\n", - "```\n", - "This [downloads the install.jl script](https://gitlab.mathematik.uni-stuttgart.de/stammbn/julia-seminar/-/raw/main/install.jl?ref_type=heads) and runs it from julia.\n", - "\n", - "### 2) Getting all the rest (expert version)\n", - "\n", - "As an alternative you can also also run the following commands manually (this requires to have `git` and `julia` available from the commandline): \n", - "```\n", - "git clone https://gitlab.mathematik.uni-stuttgart.de/stammbn/Julia-seminar/\n", - "cd Julia-seminar\n", - "julia install-manual.jl\n", - "```\n", - "\n", - "### 3) Starting the notebook\n", - "To start the notebook make sure to be in the folder `Julia-seminar` and then run `julia`: an interactive Julia command line will open. In there run this command\n", - "\n", - "```\n", - "using IJulia; notebook(dir=pwd())\n", - "```\n", - "and the notebook will automatically open in a browser.\n", - "\n", - "### Troubleshooting\n", - "If you are facing issues, check out\n", - "the [great troubleshooting section](https://carstenbauer.github.io/WorkshopWizard.jl/dev/troubleshooting/)\n", - "from the WorkshopWizard package by Carsten Bauer (which is being used by `install.jl`)." - ] - }, - { - "cell_type": "markdown", - "id": "b495d658-ab7a-41fb-819e-0fef02c10772", - "metadata": {}, - "source": [ - "## Software und Material\n", - "Der Kurs erfordert verschiedene Dinge: eine funktionierende Installation von [Julia 1.9](https://julialang.org/downloads/), [Jupyter](https://jupyter.org/), [IJulia.jl](https://github.com/JuliaLang/IJulia.jl), das Kursmaterial und verschiedene Abhängigkeiten. Um alles zu herunterzuladen und zu installieren, befolgst Du diese Schritte:\n", - "\n", - "### 1) Julia herunterladen\n", - "Um dem Kurs zu folgen, benötigst du **Julia 1.9**.\n", - "Julia kann leicht in binärer Form von den [Julia-Downloads](https://julialang.org/downloads/) bezogen werden.\n", - "\n", - "### 2) Alles andere\n", - "\n", - "Um die verbleibenden Dateien und Abhängigkeiten zu erhalten, starte `julia` und kopiere im resultierenden REPL-Shell folgenden Code:\n", - "```julia\n", - "import Downloads\n", - "script = Downloads.download(\"https://gitlab.mathematik.uni-stuttgart.de/stammbn/julia-seminar/-/raw/main/install.jl?ref_type=heads\")\n", - "include(script)\n", - "```\n", - "Das [lädt das install.jl-Skript herunter](https://gitlab.mathematik.uni-stuttgart.de/stammbn/julia-seminar/-/raw/main/install.jl?ref_type=heads) und führt es in Julia aus.\n", - "\n", - "### 2) Alles andere (Experten-Version)\n", - "\n", - "Als Alternative kannst Du auch die folgenden Befehle manuell ausführen (dies setzt voraus, dass `git` und `julia` von der Kommandozeile aus verfügbar sind):\n", - "```\n", - "git clone https://gitlab.mathematik.uni-stuttgart.de/stammbn/Julia-seminar/\n", - "cd Julia-seminar\n", - "julia install-manual.jl\n", - "```\n", - "\n", - "### 3) Starten des Notebooks\n", - "Um das Notebook zu starten, stelle sicher, dass Du Dich im Ordner `Julia-seminar` befindest, und führe dann `julia` aus: Eine interaktive Julia-Befehlszeile wird geöffnet. Führe darin folgenden Befehl aus:\n", - "\n", - "```\n", - "using IJulia; notebook(dir=pwd())\n", - "```\n", - "und das Notebook wird automatisch im Browser geöffnet.\n", - "\n", - "### Fehlerbehebung\n", - "Wenn Du auf Probleme stößt, werfe einen Blick auf den [ausgezeichneten Problembehandlungsabschnitt](https://carstenbauer.github.io/WorkshopWizard.jl/dev/troubleshooting/) aus dem WorkshopWizard-Paket von Carsten Bauer (das von `install.jl` verwendet wird)." + "# Installation und Einrichtung\n", + "Bitte befolge die in README.md beschriebenen Schritte 1-3, um Julia herunterzuladen und zu installieren, und das Notebook 0_Installation.ipynb in einen Jupyter-notebook zu öffnen." ] }, { @@ -222,7 +136,7 @@ "\n", "Schließlich können neue Zellen hinzugefügt werden, indem Du das `+`-Symbol im oberen Menü verwendest.\n", "\n", - "Jedes Mal, wenn eine Übung für den Leser übrig bleibt, haben wir eine leere Code-Zelle hinzugefügt." + "Jedes Mal, wenn es eine Übung für den Leser gibt, haben wir eine leere Code-Zelle hinzugefügt." ] }, { @@ -273,7 +187,7 @@ ], "metadata": { "kernelspec": { - "display_name": "Julia 1.9.2", + "display_name": "julia 1.9.3", "language": "julia", "name": "julia-1.9" }, diff --git a/1_Basics.ipynb b/src/1_Basics.ipynb similarity index 97% rename from 1_Basics.ipynb rename to src/1_Basics.ipynb index 3a840c942747ff2069faa2be1075c7c8ca70620b..0de4bf145272173b7693ffbede076c53f2287d42 100644 --- a/1_Basics.ipynb +++ b/src/1_Basics.ipynb @@ -217,7 +217,7 @@ "Es stellt sich heraus, dass `struct` eines der Schlüsselwörter von Julia ist und nicht als Variablennamen verwendet werden kann.\n", "\n", "- Für weitere Schlüsselwörter von Julia, siehe [https://docs.julialang.org/en/v1/base/base/#Keywords](https://docs.julialang.org/en/v1/base/base/#Keywords).\n", - "- Für weitere Details über `Variable`, siehe [https://docs.julialang.org/en/v1/manual/variables/](https://docs.julialang.org/en/v1/manual/variables/)." + "- Für weitere Details über `Variabeln`, siehe [https://docs.julialang.org/en/v1/manual/variables/](https://docs.julialang.org/en/v1/manual/variables/)." ] }, { @@ -357,7 +357,9 @@ "id": "fc538246-418c-4ebe-b487-81feba4383c8", "metadata": {}, "outputs": [], - "source": [] + "source": [ + "" + ] }, { "cell_type": "markdown", @@ -572,7 +574,7 @@ "metadata": {}, "outputs": [], "source": [ - "x = 3; y = 5\n", + "x = 3; y = 2\n", "\n", "if x < y\n", " println(\"x is less than y\")\n", @@ -606,7 +608,7 @@ "metadata": {}, "outputs": [], "source": [ - "x = 3\n", + "x = 6\n", "x < 5 ? \"smaller than 5\" : \"larger or equal 5\"" ] }, @@ -633,7 +635,7 @@ "source": [ "## Iterations\n", "\n", - "Julia implements the standard for and while constructs." + "Julia implements the standard `for` and `while` constructs." ] }, { @@ -643,7 +645,7 @@ "source": [ "## Iterationen\n", "\n", - "Julia implementiert die üblichen for- und while-Strukturen." + "Julia implementiert die üblichen `for`- und `while`-Befehle." ] }, { @@ -766,7 +768,7 @@ "id": "873c3625-3b99-48e5-9821-9b696a8f8a12", "metadata": {}, "source": [ - "Das `break`-Statement beendet die Schleife. Wenn ein `continue`-Statement in einer Schleife auftritt, springt die Kontrolle zum Anfang der Schleife für die nächste Iteration, wobei die Ausführung der Anweisungen im Körper der Schleife für die aktuelle Iteration übersprungen wird. Zum Beispiel:" + "Das `break`-Statement beendet die Schleife. Wenn ein `continue`-Statement in einer Schleife auftritt, springt die Kontrolle zum Anfang der Schleife für die nächste Iteration, wobei die Ausführung der Anweisungen im Innern der Schleife für die aktuelle Iteration übersprungen wird. Zum Beispiel:" ] }, { @@ -825,7 +827,7 @@ "\n", "$$ \\frac{1}{\\pi} = \\frac{2\\sqrt{2}}{9801} \\sum_{k=0}^\\infty \\frac{(4k)! (1103 + 26390 k)}{(k!)^4 396^{4 k}}$$\n", "\n", - "Use this formula to compute an estimate of π. It should use a while loop ot compute terms of the summation untile the last term is smaller than 1e-15. Afterwards, you can check the result by comparing it to π (to get π in Julia, write \\pi and then press TAB)." + "Use this formula to compute an estimate of π. It should use a while loop ot compute terms of the summation untile the last term is smaller than 1e-15. Afterwards, you can check the result by comparing it to π (to get π in Julia, write \\pi and then press TAB). Hint: use the builtin function `factorial`." ] }, { @@ -837,13 +839,13 @@ "\n", "$$ \\frac{1}{\\pi} = \\frac{2\\sqrt{2}}{9801} \\sum_{k=0}^\\infty \\frac{(4k)! (1103 + 26390 k)}{(k!)^4 396^{4 k}}$$\n", "\n", - "Verwenden Sie diese Formel, um eine Schätzung von π zu berechnen. Sie sollte eine While-Schleife verwenden, um die Terme der Summation zu berechnen, bis der letzte Term kleiner als 1e-15 ist. Anschließend können Sie das Ergebnis überprüfen, indem Sie es mit π vergleichen (um π in Julia zu erhalten, schreiben Sie \\pi und drücken dann die TAB-Taste).\n" + "Verwenden Sie diese Formel, um eine Schätzung von π zu berechnen. Sie sollte eine While-Schleife verwenden, um die Terme der Summation zu berechnen, bis der letzte Term kleiner als 1e-15 ist. Anschließend können Sie das Ergebnis überprüfen, indem Sie es mit π vergleichen (um π in Julia zu erhalten, schreiben Sie \\pi und drücken dann die TAB-Taste). Hinweis: Verwenden Sie die integrierte Funktion `factorial`." ] }, { "cell_type": "code", "execution_count": null, - "id": "9243c8ee-b3b9-4e23-a829-d20fc8bf0b16", + "id": "dbe40300-8333-4271-aa43-49f973fa03a6", "metadata": {}, "outputs": [], "source": [] @@ -1047,7 +1049,7 @@ "id": "9b688bbf-08b6-4fba-babe-b16b6e1119be", "metadata": {}, "source": [ - "Für Einzeiler-Funktionen kann man auch eine praktische Kurzschreibweise verwenden:" + "Beide Funktionen sind in den Argumenttypen vollständig generisch" ] }, { @@ -1348,11 +1350,11 @@ "source": [ "Es mag nicht klar sein, warum es sich lohnt, ein Programm in Funktionen zu unterteilen. Es gibt mehrere Gründe dafür:\n", "\n", - "- Das Erstellen einer neuen Funktion bietet Ihnen die Möglichkeit, eine Gruppe von Anweisungen zu benennen, was Ihr Programm leichter lesbar und einfacher zu debuggen macht.\n", + "- Das Erstellen einer neuen Funktion bietet die Möglichkeit, eine Gruppe von Anweisungen zu benennen, was das Programm leichter lesbar und einfacher zu debuggen macht.\n", "- Funktionen können ein Programm kleiner machen, indem sie wiederholten Code eliminieren. Später, wenn Sie eine Änderung vornehmen, müssen Sie sie nur an einer Stelle vornehmen.\n", "- Das Aufteilen eines langen Programms in Funktionen ermöglicht es Ihnen, die Teile nacheinander zu debuggen und dann zu einem funktionierenden Ganzen zusammenzufügen.\n", "- Gut gestaltete Funktionen sind oft für viele Programme nützlich. Sobald Sie eine geschrieben und debuggt haben, können Sie sie wiederverwenden.\n", - "- In Julia können Funktionen die Leistung erheblich verbessern.\n" + "- In Julia können Funktionen die Schnelligkeit erheblich verbessern.\n" ] }, { @@ -1589,7 +1591,7 @@ "id": "d9c31712-941c-4611-99e5-b33cdb12e28f", "metadata": {}, "source": [ - " - Then write a function that computes bynomial coefficients\n", + " - Then write a function that computes binomial coefficients\n", "$$ \\left(\\begin{array}{c} n \\\\ k \\end{array}\\right) = \\frac{n!}{k! (n-k)!} $$\n", " by calling the function of the previous points." ] @@ -1626,7 +1628,7 @@ "id": "a32900cc-c244-4d63-8ff6-4d11cee83eee", "metadata": {}, "source": [ - " - Verwenden Sie die beiden Funktionen, um zu berechnen\n", + " - Verwenden Sie die beiden Funktionen, um folgendes zu berechnen\n", "$$ 15! \\qquad \\left(\\begin{array}{c} 5 \\\\ 2 \\end{array}\\right) \\qquad \\left(\\begin{array}{c} 5 \\\\ 3 \\end{array}\\right) $$" ] }, @@ -1678,7 +1680,8 @@ "outputs": [], "source": [ "greet(\"Michele\")\n", - "greet(\"Lambert\"; greeting=\"Hallo\")" + "greet(\"Lambert\"; greeting=\"Hallo\")\n", + "greet(\"YingXing\"; greeting=\"你好\")" ] }, { @@ -1697,7 +1700,7 @@ "metadata": {}, "source": [ "Dies ist in den folgenden Fällen sehr praktisch:\n", - " - um ein Standardverhalten der Funktion festzulegen, während die Möglichkeit besteht, es fein zu steuern.\n", + " - um ein Standardverhalten der Funktion festzulegen, während die Möglichkeit besteht, sie fein zu steuern.\n", " - um zu einem späteren Zeitpunkt neue Funktionalitäten hinzuzufügen, ohne die Abwärtskompatibilität zu brechen." ] }, diff --git a/2_Advanced_Data_Types.ipynb b/src/2_Advanced_Data_Types.ipynb similarity index 95% rename from 2_Advanced_Data_Types.ipynb rename to src/2_Advanced_Data_Types.ipynb index 9b18641c3e5e85ffacfb9eaae194d6e8587e84ea..99d85be9b6dc93323eae0da1ab1f7126833eb988 100644 --- a/2_Advanced_Data_Types.ipynb +++ b/src/2_Advanced_Data_Types.ipynb @@ -29,7 +29,7 @@ "id": "8ffb53e2-1813-4fdf-962e-e066bc9b737c", "metadata": {}, "source": [ - "## Wörterbücher" + "## Zuordnungstabellen (assoziative Listen)" ] }, { @@ -39,7 +39,7 @@ "source": [ "A dictionary contains a collection of indices, which are called keys, and a collection of values. Each key is associated with a single value. The association of a key and a value is called a key-value pair or sometimes an item.\n", "\n", - "The function `Dict` creates a new dictionary with no items. Because Dict is the name of a built-in function, you should avoid using it as a variable name. " + "The function `Dict` creates a new dictionary with no items. Because `Dict` is the name of a built-in function, you should avoid using it as a variable name. " ] }, { @@ -47,9 +47,9 @@ "id": "548487ed-dc9d-4404-a2ab-451c0ea742e4", "metadata": {}, "source": [ - "Ein Wörterbuch enthält eine Sammlung von Indizes, die als Schlüssel bezeichnet werden, und eine Sammlung von Werten. Jeder Schlüssel ist mit einem einzigen Wert verbunden. Die Zuordnung eines Schlüssels und eines Wertes wird als Schlüssel-Wert-Paar oder manchmal als Element bezeichnet.\n", + "Eine Zuordnungstabelle enthält eine Sammlung von Indizes, die als Schlüssel bezeichnet werden, und eine Sammlung von Werten. Jeder Schlüssel ist mit einem einzigen Wert verbunden. Die Zuordnung eines Schlüssels und eines Wertes wird als Schlüssel-Wert-Paar oder manchmal als Element bezeichnet.\n", "\n", - "Die Funktion `Dict` erstellt ein neues Wörterbuch ohne Elemente. Da Dict der Name einer integrierten Funktion ist, sollte man ihn vermeiden, als Variablenname zu verwenden." + "Die Funktion `Dict` erstellt ein neues Wörterbuch ohne Elemente. Da `Dict` der Name einer integrierten Funktion ist, sollte man vermeiden ihn als Variablenname zu verwenden." ] }, { @@ -85,7 +85,7 @@ "id": "09b62b4d-748b-4e1d-91f2-7db610ad02ac", "metadata": {}, "source": [ - "Du kannst auch ein Wörterbuch mit Elementen initialisieren, wie folgt:" + "Du kannst auch eine Zuordnungstabelle mit Elementen wie folgt initialisieren:" ] }, { @@ -168,7 +168,7 @@ "id": "84cf8b52-f061-4b28-a327-bc527820517c", "metadata": {}, "source": [ - "Wenn der Schlüssel nicht im Wörterbuch vorhanden ist, tritt eine Ausnahme auf:" + "Wenn der Schlüssel nicht im Wörterbuch vorhanden ist, tritt eine Fehlermeldung auf:" ] }, { @@ -194,7 +194,7 @@ "id": "f83d51c5-2c1d-4449-8cd5-e80f224b9a76", "metadata": {}, "source": [ - "Die Funktion `length` funktioniert auch bei Wörterbüchern; sie gibt die Anzahl der Schlüssel-Wert-Paare zurück:" + "Die Funktion `length` funktioniert auch bei Zuordnungstabellen; sie gibt die Anzahl der Schlüssel-Wert-Paare zurück:" ] }, { @@ -302,9 +302,9 @@ "id": "5b255b31-8aca-49b4-a95f-302c59baa975", "metadata": {}, "source": [ - "### Schleifen über Wörterbücher\n", + "### Schleifen über Zuordnungstabellen\n", "\n", - "Du kannst die Schlüssel des Wörterbuchs in einer `for`-Schleife durchlaufen." + "Du kannst die Schlüssel der Zuordnungstabelle in einer `for`-Schleife durchlaufen." ] }, { @@ -360,7 +360,7 @@ "id": "8daa9d3e-19de-4415-ba6c-6aeb174b38fa", "metadata": {}, "source": [ - "### Exercises\n", + "### Exercise\n", " - Write a function that given a string as input counts how many times each letter appears. Use a dictionary." ] }, @@ -369,7 +369,7 @@ "id": "964165ee-4d0d-4122-b6b2-d3926101cab2", "metadata": {}, "source": [ - "### Übungen\n", + "### Übung\n", " - Schreibe eine Funktion, die bei Eingabe eines Strings zählt, wie oft jeder Buchstabe vorkommt. Verwende ein Wörterbuch." ] }, @@ -738,7 +738,7 @@ "id": "db3cd00d-d41c-4f68-95d4-c4e5b283734a", "metadata": {}, "source": [ - "Aber wenn du das Tupel verteilst, funktioniert es:" + "Wenn du aber das Tupel verteilst, funktioniert es:" ] }, { @@ -765,7 +765,7 @@ "id": "dad5d7bf-0dd5-450b-90f3-7768f2d91c18", "metadata": {}, "source": [ - "### Wörterbücher und Tupel" + "### Zuordnungstabellen und Tupel" ] }, { @@ -781,7 +781,7 @@ "id": "3a38cabd-b056-4140-a75c-e0fa383a2a74", "metadata": {}, "source": [ - "Wörterbücher können als Iteratoren verwendet werden, um die Schlüssel-Wert-Paare zu durchlaufen. Du kannst es in einer `for`-Schleife wie folgt verwenden:\n" + "Zuordnungstabellen können als Iteratoren verwendet werden, um die Schlüssel-Wert-Paare zu durchlaufen. Du kannst es in einer `for`-Schleife wie folgt verwenden:\n" ] }, { @@ -810,7 +810,7 @@ "id": "5a012731-cf42-487b-9d02-4a4b1d0475c0", "metadata": {}, "source": [ - "Es ist üblich, Tupel als Schlüssel in Wörterbüchern zu verwenden. Zum Beispiel könnte ein Telefonverzeichnis Nachname-Vorname-Paare auf Telefonnummern abbilden. Angenommen, wir haben last, first und number definiert, könnten wir schreiben:" + "Es ist üblich, Tupel als Schlüssel in Zuordnungstabellen zu verwenden. Zum Beispiel könnte ein Telefonverzeichnis Nachname-Vorname-Paare auf Telefonnummern abbilden. Angenommen, wir haben last, first und number definiert, könnten wir schreiben:" ] }, { @@ -895,7 +895,7 @@ "id": "347fe4ea-5b63-4fb8-91bc-2b7b8a0c6a30", "metadata": {}, "source": [ - "### Exercises\n", + "### Exercise\n", " - Write a function `swap_first_last` that takes a tuple and returns a new tuple with the first and last elements swapped. Tip: use a combination of the `...` operator and of this slice `[2:end-1]`." ] }, @@ -904,8 +904,8 @@ "id": "70061322-9435-496a-ac0d-c026f41e5936", "metadata": {}, "source": [ - "### Exercises\n", - " - Write a function `swap_first_last` that takes a tuple and returns a new tuple with the first and last elements swapped. Tip: use a combination of the `...` operator and of this slice `[2:end-1]`." + "### Übung\n", + " - Schreibe eine Funktion `swap_first_last`, die ein Tupel entgegennimmt und ein neues Tupel zurückgibt, bei dem das erste und das letzte Element vertauscht sind. Tipp: Verwende eine Kombination des `...`-Operators und des Slices `[2:end-1]`.\n" ] }, { @@ -1150,7 +1150,7 @@ "id": "06f44f63-bf8e-45f5-9495-006e21fc7560", "metadata": {}, "source": [ - "Eine dritte Option ist es, einige Felder einer unveränderlichen Struktur als veränderbar zu definieren. Zum Beispiel kann ein Wörterbuch innerhalb einer unveränderlichen Struktur geändert werden." + "Eine dritte Option ist es, einige Felder einer unveränderlichen Struktur als veränderbar zu definieren. Zum Beispiel kann eine Zuordnungstabellen innerhalb einer unveränderlichen Struktur geändert werden." ] }, { @@ -1354,7 +1354,7 @@ "id": "79339467-8994-4a5c-8987-3420d14cb290", "metadata": {}, "source": [ - "If a new, distinct, object is needed (in other words, a copy by value), we can use the function `deepcopy`. " + "Wenn ein neues, eindeutiges Objekt benötigt wird (mit anderen Worten, eine Kopie nach Wert), können wir die Funktion `deepcopy` verwenden." ] }, { @@ -1644,7 +1644,7 @@ ], "metadata": { "kernelspec": { - "display_name": "Julia 1.9.3", + "display_name": "julia 1.9.3", "language": "julia", "name": "julia-1.9" }, diff --git a/src/README.md b/src/README.md new file mode 100644 index 0000000000000000000000000000000000000000..a3c216df53f849d9272b5752f31ae914352b9c0f --- /dev/null +++ b/src/README.md @@ -0,0 +1,42 @@ +# For developers + +## Setting up `pre-commit` + +[`pre-commit`](https://pre-commit.com/) is a framework that helps to manage and maintain pre-commit hooks to ensure that your code adheres to a consistent style, prevents errors, and adheres to other quality assurance checks. + +1. **Install `pre-commit`:** + To ensure smooth development, install `pre-commit` using pip by running the following command: + + ```bash + pip install pre-commit + ``` + + For more information and installation options, visit the [`pre-commit`](https://pre-commit.com/) website. + +2. **Navigate to the project directory:** + Change into the project directory, i.e., `julia-seminar` by running: + + ```bash + cd julia-seminar + ``` + +3. **Install hooks:** + Install the git hooks by executing: + + ```bash + pre-commit install + ``` + + This command installs the pre-commit script alongside existing git hooks. + +Once the pre-commit hook is installed, it will automatically check your code for any issues before each commit. If the checks do not pass, you will be prompted to fix them before proceeding. + +## Localizing the notebooks + +1. Make sure the bilingual version of the notebook is in the folder `src/`. This is for clarity reasons. + +2. Run `./localize.py bilingual_notebook.ipynb`. The script will ask for your help whenever it is unclear. +You should help it to set the language of the cell to one among `en`, `de` and `eq`. +The kind `eq` is for everything that is not a spoken language (figures, schemes, equations and similar). + +3. You will get two versions in the `src/` folder. Move them to the root directory, add them to git and commit. diff --git a/src/localize.py b/src/localize.py new file mode 100755 index 0000000000000000000000000000000000000000..05b2d8d39241db941e0c2eeab58b9dcc971093f2 --- /dev/null +++ b/src/localize.py @@ -0,0 +1,85 @@ +#!/usr/bin/python3 + +import copy +import json +import os +import sys + +import langid + + +def detect_language(text): + return langid.classify(text) + + +def load(path): + with open(path, encoding="utf-8") as file: + notebook = json.load(file) + return notebook + + +def human_intervention(language, probability, text): + print( + f"I classified this text:\n`{text}`\nas {language} with a non normalized probability of {probability}.\n" + ) + while True: + print( + "Can you help me identifying it? write one among 'en', 'de', 'eq' (for equations), then press enter" + ) + language = input() + if language in ["en", "de", "eq"]: + print("\n\n") + return language + + +def write(path, notebook): + with open(path, "w", encoding="utf-8") as file: + json.dump(notebook, file, indent=4) + + +def assign_languages(notebook): + cells = notebook["cells"] + + for i, cell in enumerate(cells): + if cell["cell_type"] == "markdown": + text = str(cell["source"]).strip("\n# []'") + language, probability = detect_language(text) + + if probability >= -10 or language not in ["en", "de"]: + # langid is doing something strange, we need to intervene + language = human_intervention(language, probability, text) + + notebook["cells"][i]["metadata"]["natural_language"] = language + + +def select_language(notebook, language): + cells = notebook["cells"] + + selected_cells = [] + for cell in cells: + if cell["cell_type"] == "markdown": + if cell["metadata"]["natural_language"] == language: + selected_cells.append(cell) + elif cell["metadata"]["natural_language"] == "eq": + selected_cells.append(cell) + else: + selected_cells.append(cell) + + new_notebook = copy.deepcopy(notebook) + new_notebook["cells"] = selected_cells + + return new_notebook + + +if __name__ == "__main__": + PATH = sys.argv[1] + BASENAME = os.path.splitext(os.path.basename(PATH))[0] + + NOTEBOOK = load(PATH) + assign_languages(NOTEBOOK) + + NOTEBOOK_EN = select_language(NOTEBOOK, "en") + NOTEBOOK_DE = select_language(NOTEBOOK, "de") + + write(f"{BASENAME}_en.ipynb", NOTEBOOK_EN) + write(f"{BASENAME}_de.ipynb", NOTEBOOK_DE)