{ "cells": [ { "cell_type": "markdown", "id": "fcc03529", "metadata": {}, "source": [ "# Container\n", "\n", "\n", "Julia bietet eine große Auswahl von Containertypen mit weitgehend ähnlichem Interface an. \n", "Wir stellen hier `Tuple`, `Range`, `Array`, `Vector` und `Matrix` vor. \n", "\n", "Diese Container sind: \n", "\n", "- **iterierbar:** Man kann über die Elemente des Containers iterieren: \n", "```julia \n", "for x ∈ container ... end\n", "```\n", "- **indizierbar:** Man kann auf Elemente über ihren Index zugreifen: \n", "```julia\n", "x = container[i]\n", "``` \n", "und einige sind \n", "\n", "- **mutierbar** (nur `Array`, `Vector` und `Matrix`): Man kann Elemente hinzufügen, entfernen und ändern.\n", "\n", "Weiterhin gibt es eine Reihe gemeinsamer Funktionen, z.B.\n", "\n", "- `length(container)` --- Anzahl der Elemente\n", "- `eltype(container)` --- Typ der Elemente\n", "- `isempty(container)` --- Test, ob Container leer ist\n", "- `empty!(container)` --- leert Container (nur wenn mutierbar)\n", "\n", "\n", "## Tupeln\n", "\n", "Ein Tupel ist ein nicht mutierbarer Container von Elementen. Es ist also nicht möglich, neue Elemente dazuzufügen oder den Wert eines Elements zu ändern. \n" ] }, { "cell_type": "code", "execution_count": null, "id": "3b33212e", "metadata": {}, "outputs": [], "source": [ "t = (33, 4.5, \"Hello\")\n", "\n", "@show t[2] # indizierbar\n", "\n", "for i ∈ t println(i) end # iterierbar" ] }, { "cell_type": "markdown", "id": "e65e4da8", "metadata": {}, "source": [ "Ein Tupel ist ein **inhomogener** Typ. Jedes Element hat seinen eigenen Typ und das zeigt sich auch im Typ des Tupels:\n" ] }, { "cell_type": "code", "execution_count": null, "id": "3d21cc5b", "metadata": {}, "outputs": [], "source": [ "typeof(t)" ] }, { "cell_type": "markdown", "id": "74fcc47e", "metadata": {}, "source": [ "Man verwendet Tupel gerne als Rückgabewerte von Funktionen, um mehr als ein Objekt zurückzulieferen.\n" ] }, { "cell_type": "code", "execution_count": null, "id": "6ffc0cdc", "metadata": {}, "outputs": [], "source": [ "# Ganzzahldivision und Rest: \n", "# Quotient und Rest werden den Variablen q und r zugewiesen\n", "\n", "q, r = divrem(71, 6)\n", "@show q r;" ] }, { "cell_type": "markdown", "id": "e7a04cdd", "metadata": {}, "source": [ "Wie man hier sieht, kann man in bestimmten Konstrukten die Klammern auch weglassen.\n", "Dieses *implict tuple packing/unpacking* verwendet man auch gerne in Mehrfachzuweisungen:\n" ] }, { "cell_type": "code", "execution_count": null, "id": "2a260b6e", "metadata": {}, "outputs": [], "source": [ "x, y, z = 12, 17, 203" ] }, { "cell_type": "code", "execution_count": null, "id": "3447dffb", "metadata": {}, "outputs": [], "source": [ "y" ] }, { "cell_type": "markdown", "id": "8694ec4a", "metadata": {}, "source": [ "Manche Funktionen bestehen auf Tupeln als Argument oder geben immer Tupeln zurück. Dann braucht man manchmal ein Tupel aus einem Element. \n", "\n", "Das notiert man so:\n" ] }, { "cell_type": "code", "execution_count": null, "id": "24856f9b", "metadata": {}, "outputs": [], "source": [ "x = (13,) # ein 1-Element-Tupel" ] }, { "cell_type": "markdown", "id": "11ac465d", "metadata": {}, "source": [ "Das Komma - und nicht die Klammern -- macht das Tupel. \n" ] }, { "cell_type": "code", "execution_count": null, "id": "87474e9d", "metadata": {}, "outputs": [], "source": [ "x= (13) # kein Tupel" ] }, { "cell_type": "markdown", "id": "da35087d", "metadata": {}, "source": [ "## Ranges\n", "\n", "Wir haben *range*-Objekte schon in numerischen `for`-Schleifen verwendet.\n" ] }, { "cell_type": "code", "execution_count": null, "id": "3bfc9415", "metadata": {}, "outputs": [], "source": [ "r = 1:1000\n", "typeof(r)" ] }, { "cell_type": "markdown", "id": "7d2c6838", "metadata": {}, "source": [ "Es gibt verschiedene *range*-Typen. Wie man sieht, sind es über den Zahlentyp parametrisierte Typen und `UnitRange` ist z.B. ein *range* mit der Schrittweite 1. Ihre Konstruktoren heißen in der Regel `range()`. \n", "\n", "Der Doppelpunkt ist eine spezielle Syntax. \n", "\n", "- `a:b` wird vom Parser umgesetzt zu `range(a, b)` \n", "- `a:b:c` wird umgesetzt zu `range(a, c, step=b)`\n", "\n", "\n", "*Ranges* sind offensichtlich iterierbar, nicht mutierbar aber indizierbar.\n" ] }, { "cell_type": "code", "execution_count": null, "id": "28aecb9e", "metadata": {}, "outputs": [], "source": [ "(3:100)[20] # das zwanzigste Element" ] }, { "cell_type": "markdown", "id": "350affb7", "metadata": {}, "source": [ "Wir erinnern an die Semantik der `for`-Schleife: `for i in 1:1000` heißt **nicht**:\n", "\n", "- 'Die Schleifenvariable `i` wird bei jedem Durchlauf um eins erhöht' **sondern** \n", "- 'Der Schleifenvariable werden nacheinander die Werte 1,2,3,...,1000 aus dem Container zugewiesen'. \n", "\n", "Allerdings wäre es sehr ineffektiv, diesen Container tatsächlich explizit anzulegen. \n", "\n", "- _Ranges_ sind \"lazy\" Vektoren, die nie wirklich irgendwo als konkrete Liste abgespeichert werden. Das macht sie als Iteratoren in `for`-Schleifen so nützlich: speichersparend und schnell.\n", "- Sie sind 'Rezepte' oder Generatoren, die auf die Abfrage 'Gib mir dein nächstes Element!' antworten.\n", "- Tatsächlich ist der Muttertyp `AbstractRange` ein Subtyp von `AbstractVector`.\n", "\n", "Das Macro `@allocated` gibt aus, wieviel Bytes an Speicher bei der Auswertung eines Ausdrucks alloziert wurden.\n" ] }, { "cell_type": "code", "execution_count": null, "id": "14ea84bd", "metadata": {}, "outputs": [], "source": [ "@allocated [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]" ] }, { "cell_type": "code", "execution_count": null, "id": "c900fd32", "metadata": {}, "outputs": [], "source": [ "@allocated 1:20" ] }, { "cell_type": "markdown", "id": "0a763f8b", "metadata": {}, "source": [ "Zum Umwandeln in einen 'richtigen' Vektor dient die Funktion `collect()`.\n" ] }, { "cell_type": "code", "execution_count": null, "id": "0e0be9dd", "metadata": {}, "outputs": [], "source": [ "collect(20:-3:1)" ] }, { "cell_type": "markdown", "id": "568f2f9f", "metadata": {}, "source": [ "Recht nützlich, z.B. beim Vorbereiten von Daten zum Plotten, ist der *range*-Typ `LinRange`.\n" ] }, { "cell_type": "code", "execution_count": null, "id": "8596862b", "metadata": {}, "outputs": [], "source": [ "LinRange(2, 50, 300)" ] }, { "cell_type": "markdown", "id": "f148954b", "metadata": {}, "source": [ "`LinRange(start, stop, n)` erzeugt eine äquidistante Liste von `n` Werten von denen der erste und der letzte die vorgegebenen Grenzen sind. \n", "Mit `collect()` kann man bei Bedarf auch daraus den entsprechenden Vektor gewinnen.\n" ] } ], "metadata": { "kernelspec": { "display_name": "Julia 1.8.5", "language": "julia", "name": "julia-1.8" } }, "nbformat": 4, "nbformat_minor": 5 }