304 lines
7.6 KiB
Plaintext
304 lines
7.6 KiB
Plaintext
|
{
|
||
|
"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
|
||
|
}
|