english translation started

This commit is contained in:
2026-02-22 18:22:46 +01:00
parent 19c67a3c9b
commit 9e418381ca
17 changed files with 1915 additions and 1907 deletions

View File

@@ -2,73 +2,65 @@
engine: julia
---
```{julia}
#| error: false
#| echo: false
#| output: false
using InteractiveUtils
```
# Containers
Julia offers a wide selection of container types with largely similar interfaces.
We introduce `Tuple`, `Range`, and `Dict` here, and in the next chapter we will cover `Array`, `Vector`, and `Matrix`.
# Container
These containers are:
Julia bietet eine große Auswahl von Containertypen mit weitgehend ähnlichem Interface an.
Wir stellen hier `Tuple`, `Range` und `Dict` vor, im nächsten Kapitel dann `Array`, `Vector` und `Matrix`.
Diese Container sind:
- **iterierbar:** Man kann über die Elemente des Containers iterieren:
- **iterable:** You can iterate over the elements of the container:
```julia
for x ∈ container ... end
```
- **indizierbar:** Man kann auf Elemente über ihren Index zugreifen:
- **indexable:** You can access elements via their index:
```julia
x = container[i]
```
und einige sind auch
```
and some are also
- **mutierbar**: Man kann Elemente hinzufügen, entfernen und ändern.
- **mutable:** You can add, remove, and modify elements.
Weiterhin gibt es eine Reihe gemeinsamer Funktionen, z.B.
Furthermore, there are several common functions, e.g.,
- `length(container)` --- Anzahl der Elemente
- `eltype(container)` --- Typ der Elemente
- `isempty(container)` --- Test, ob Container leer ist
- `empty!(container)` --- leert Container (nur wenn mutierbar)
- `length(container)` --- number of elements
- `eltype(container)` --- type of elements
- `isempty(container)` --- test whether container is empty
- `empty!(container)` --- empties container (only if mutable)
## Tupeln
## Tuples
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.
A tuple is an immutable container of elements. It is therefore not possible to add new elements or change the value of an element.
```{julia}
t = (33, 4.5, "Hello")
@show t[2] # indizierbar
@show t[2] # indexable
for i ∈ t println(i) end # iterierbar
for i ∈ t println(i) end # iterable
```
Ein Tupel ist ein **inhomogener** Typ. Jedes Element hat seinen eigenen Typ und das zeigt sich auch im Typ des Tupels:
A tuple is an **inhomogeneous** type. Each element has its own type, which is reflected in the tuple's type:
```{julia}
typeof(t)
```
Man verwendet Tupel gerne als Rückgabewerte von Funktionen, um mehr als ein Objekt zurückzulieferen.
Tuples are frequently used as function return values to return more than one object.
```{julia}
# Ganzzahldivision und Rest:
# Quotient und Rest werden den Variablen q und r zugewiesen
# Integer division and remainder:
# quotient and remainder are assigned to variables q and r
q, r = divrem(71, 6)
@show q r;
```
Wie man hier sieht, kann man in bestimmten Konstrukten die Klammern auch weglassen.
Dieses *implict tuple packing/unpacking* verwendet man auch gerne in Mehrfachzuweisungen:
As you can see here, parentheses can be omitted in certain constructs.
This *implicit tuple packing/unpacking* is also commonly used in multiple assignments:
```{julia}
@@ -80,56 +72,59 @@ x, y, z = 12, 17, 203
y
```
Manche Funktionen bestehen auf Tupeln als Argument oder geben immer Tupeln zurück. Dann braucht man manchmal ein Tupel aus einem Element.
Some functions require tuples as arguments or always return tuples. Then you sometimes need a tuple with a single element.
Das notiert man so:
This is written as:
```{julia}
x = (13,) # ein 1-Element-Tupel
x = (13,) # a 1-element tuple
```
Das Komma - und nicht die Klammern -- macht das Tupel.
The comma - not the parentheses - makes the tuple.
```{julia}
x= (13) # kein Tupel
x= (13) # not a tuple
```
## Ranges
Wir haben *range*-Objekte schon in numerischen `for`-Schleifen verwendet.
We have already used *range* objects in numerical `for` loops.
```{julia}
r = 1:1000
typeof(r)
```
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()`.
There are various *range* types. As you can see, they are parameterized types based on the numeric type, and `UnitRange` is, for example, a *range* with step size 1. Their constructors are usually named `range()`.
Der Doppelpunkt ist eine spezielle Syntax.
The colon is a special syntax.
- `a:b` wird vom Parser umgesetzt zu `range(a, b)`
- `a:b:c` wird umgesetzt zu `range(a, c, step=b)`
- `a:b` is parsed as `range(a, b)`
- `a:b:c` is parsed as `range(a, c, step=b)`
*Ranges* sind offensichtlich iterierbar, nicht mutierbar aber indizierbar.
*Ranges* are obviously iterable, not mutable, but indexable.
```{julia}
(3:100)[20] # das zwanzigste Element
(3:100)[20] # the 20th element
```
Wir erinnern an die Semantik der `for`-Schleife: `for i in 1:1000` heißt **nicht**:
- 'Die Schleifenvariable `i` wird bei jedem Durchlauf um eins erhöht' **sondern**
- 'Der Schleifenvariable werden nacheinander die Werte 1,2,3,...,1000 aus dem Container zugewiesen'.
Recall the semantics of the `for` loop: `for i in 1:1000` means **not**:
Allerdings wäre es sehr ineffektiv, diesen Container tatsächlich explizit anzulegen.
- 'The loop variable `i` is incremented by one in each iteration' **but rather**
- 'The loop variable is successively assigned the values 1,2,3,...,1000 from the container'.
- _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.
- Sie sind 'Rezepte' oder Generatoren, die auf die Abfrage 'Gib mir dein nächstes Element!' antworten.
- Tatsächlich ist der Muttertyp `AbstractRange` ein Subtyp von `AbstractVector`.
However, it would be very inefficient to actually create this container explicitly.
Das Macro `@allocated` gibt aus, wieviel Bytes an Speicher bei der Auswertung eines Ausdrucks alloziert wurden.
- _Ranges_ are "lazy" vectors that are never really stored as a concrete list anywhere. This makes them so useful as iterators in `for` loops: memory-efficient and fast.
- They are "recipes" or generators that respond to the query "Give me your next element!".
- In fact, the supertype `AbstractRange` is a subtype of `AbstractVector`.
The macro `@allocated` outputs how many bytes of memory were allocated during the evaluation of an expression.
```{julia}
@allocated r = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]
@@ -142,34 +137,35 @@ Das Macro `@allocated` gibt aus, wieviel Bytes an Speicher bei der Auswertung ei
Zum Umwandeln in einen 'richtigen' Vektor dient die Funktion `collect()`.
The function `collect()` is used to convert to a "real" vector.
```{julia}
collect(20:-3:1)
```
Recht nützlich, z.B. beim Vorbereiten von Daten zum Plotten, ist der *range*-Typ `LinRange`.
Quite useful, e.g., when preparing data for plotting, is the *range* type `LinRange`.
```{julia}
LinRange(2, 50, 300)
```
`LinRange(start, stop, n)` erzeugt eine äquidistante Liste von `n` Werten von denen der erste und der letzte die vorgegebenen Grenzen sind.
Mit `collect()` kann man bei Bedarf auch daraus den entsprechenden Vektor gewinnen.
`LinRange(start, stop, n)` generates an equidistant list of `n` values where the first and last are the specified limits.
With `collect()` you can also obtain the corresponding vector if needed.
## Dictionaries
- _Dictionaries_ (deutsch: "assoziative Liste" oder "Zuordnungstabelle" oder ...) sind spezielle Container.
- Einträge in einem Vektor `v` sind durch einen Index 1,2,3.... addressierbar: `v[i]`
- Einträge in einem _dictionary_ sind durch allgemeinere _keys_ addressierbar.
- Ein _dictionary_ ist eine Ansammlung von _key-value_-Paaren.
- Damit haben _dictionaries_ in Julia den parametrisierten Typ `Dict{S,T}`, wobei `S` der Typ der _keys_ und `T` der Typ der _values_ ist
- _Dictionaries_ (German: "associative list" or "lookup table" or ...) are special containers.
- Entries in a vector `v` are addressable by an index 1,2,3....: `v[i]`
- Entries in a _dictionary_ are addressable by more general _keys_.
- A _dictionary_ is a collection of _key-value_ pairs.
- Thus, _dictionaries_ in Julia have the parameterized type `Dict{S,T}`, where `S` is the type of _keys_ and `T` is the type of _values_.
Man kann sie explizit anlegen:
They can be created explicitly:
```{julia}
# Einwohner 2020 in Millionen, Quelle: wikipedia
# Population in 2020 in millions, source: wikipedia
EW = Dict("Berlin" => 3.66, "Hamburg" => 1.85,
"München" => 1.49, "Köln" => 1.08)
@@ -180,29 +176,29 @@ EW = Dict("Berlin" => 3.66, "Hamburg" => 1.85,
typeof(EW)
```
und mit den _keys_ indizieren:
and indexed with the _keys_:
```{julia}
EW["Berlin"]
```
Das Abfragen eines nicht existierenden _keys_ ist natürlich ein Fehler.
Of course, querying a non-existent _key_ is an error.
```{julia}
EW["Leipzig"]
```
Man kann ja auch vorher mal anfragen...
You can also ask beforehand...
```{julia}
haskey(EW, "Leipzig")
```
... oder die Funktion `get(dict, key, default)` benutzen, die bei nicht existierendem Key keinen Fehler wirft sondern das 3. Argument zurückgibt.
... or use the function `get(dict, key, default)`, which does not throw an error for non-existent keys but returns the third argument.
```{julia}
@show get(EW, "Leipzig", -1) get(EW, "Berlin", -1);
```
Man kann sich auch alle `keys` und `values` als spezielle Container geben lassen.
You can also request all `keys` and `values` as special containers.
```{julia}
keys(EW)
```
@@ -213,24 +209,24 @@ values(EW)
```
Man kann über die `keys` iterieren...
You can iterate over the `keys`...
```{julia}
for i in keys(EW)
n = EW[i]
println("Die Stadt $i hat $n Millionen Einwohner.")
println("The city $i has $n million inhabitants.")
end
```
odere gleich über `key-value`-Paare.
or directly over `key-value` pairs.
```{julia}
for (stadt, ew) ∈ EW
println("$stadt : $ew Mill.")
println("$stadt : $ew Million.")
end
```
### Erweitern und Modifizieren
### Extending and Modifying
Man kann in ein `Dict` zusätzliche `key-value`-Paare eintragen...
You can add additional `key-value` pairs to a `Dict`...
```{julia}
EW["Leipzig"] = 0.52
EW["Dresden"] = 0.52
@@ -238,42 +234,42 @@ EW
```
und einen `value` ändern.
and change a `value`.
```{julia}
# Oh, das war bei Leipzig die Zahl von 2010, nicht 2020
# Oh, the Leipzig number was from 2010, not 2020
EW["Leipzig"] = 0.597
EW
```
Ein Paar kann über seinen `key` auch gelöscht werden.
A pair can also be deleted via its `key`.
```{julia}
delete!(EW, "Dresden")
```
Zahlreiche Funktionen können mit `Dicts` wie mit anderen Containern arbeiten.
Many functions can work with `Dicts` like with other containers.
```{julia}
maximum(values(EW))
```
### Anlegen eines leeren Dictionaries
### Creating an Empty Dictionary
Ohne Typspezifikation ...
Without type specification ...
```{julia}
d1 = Dict()
```
und mit Typspezifikation:
and with type specification:
```{julia}
d2 = Dict{String, Int}()
```
### Umwandlung in Vektoren: `collect()`
### Conversion to Vectors: `collect()`
- `keys(dict)` und `values(dict)` sind spezielle Datentypen.
- Die Funktion `collect()` macht daraus eine Liste vom Typ `Vector`.
- `collect(dict)` liefert eine Liste vom Typ `Vector{Pair{S,T}}`
- `keys(dict)` and `values(dict)` are special data types.
- The function `collect()` converts them to a `Vector` type.
- `collect(dict)` returns a list of type `Vector{Pair{S,T}}`
```{julia}
@@ -285,55 +281,55 @@ collect(EW)
collect(keys(EW)), collect(values(EW))
```
### Geordnetes Iterieren über ein Dictionary
### Ordered Iteration over a Dictionary
Wir sortieren die Keys. Als Strings werden sie alphabetisch sortiert. Mit dem `rev`-Parameter wird rückwärts sortiert.
We sort the keys. As strings, they are sorted alphabetically. With the `rev` parameter, sorting is done in reverse order.
```{julia}
for k in sort(collect(keys(EW)), rev = true)
n = EW[k]
println("$k hat $n Millionen Einw. ")
println("$k has $n million inhabitants ")
end
```
Wir sortieren `collect(dict)`. Das ist ein Vektor von Paaren. Mit `by` definieren wir, wonach zu sortieren ist: nach dem 2. Element des Paares.
We sort `collect(dict)`. This is a vector of pairs. With `by` we define what to sort by: the second element of the pair.
```{julia}
for (k,v) in sort(collect(EW), by = pair -> last(pair), rev=false)
println("$k hat $v Mill. EW")
println("$k has $v million inhabitants")
end
```
### Eine Anwendung von Dictionaries: Zählen von Häufigkeiten
### An Application of Dictionaries: Counting Frequencies
Wir machen 'experimentelle Stochastik' mit 2 Würfeln:
We do "experimental probability" with 2 dice:
Gegeben sei `l`, eine Liste mit den Ergebnissen von 100 000 Pasch-Würfen, also 100 000 Zahlen zwischen 2 und 12.
Given `l`, a list with the results of 100,000 double dice rolls, i.e., 100,000 numbers between 2 and 12.
Wie häufig sind die Zahlen 2 bis 12?
How frequently do the numbers 2 to 12 occur?
Wir (lassen) würfeln:
We (let) roll:
```{julia}
l = rand(1:6, 100_000) .+ rand(1:6, 100_000)
```
Wir zählen mit Hilfe eines Dictionaries die Häufigkeiten der Ereignisse. Dazu nehmen wir das Ereignis als `key` und seine Häufigkeit als `value`.
We count the frequencies of the events using a dictionary. We take the event as the `key` and its frequency as the `value`.
```{julia}
# In diesem Fall könnte man das auch mit einem einfachen Vektor
# lösen. Eine bessere Illustration wäre z.B. Worthäufigkeit in
# einem Text. Dann ist i keine ganze Zahl sondern ein Wort=String
# In this case, one could also solve this with a simple vector.
# A better illustration would be, e.g., word frequency in
# a text. Then i is not an integer but a word=string
d = Dict{Int,Int}() # das Dict zum 'reinzählen'
d = Dict{Int,Int}() # the dict for counting
for i in l # für jedes i wird d[i] erhöht.
for i in l # for each i, d[i] is incremented.
d[i] = get(d, i, 0) + 1
end
d
```
Das Ergebnis:
The result:
```{julia}
using Plots
@@ -341,7 +337,6 @@ using Plots
plot(collect(keys(d)), collect(values(d)), seriestype=:scatter)
```
##### Das Erklär-Bild dazu:
##### The explanatory image:
[https://math.stackexchange.com/questions/1204396/why-is-the-sum-of-the-rolls-of-two-dices-a-binomial-distribution-what-is-define](https://math.stackexchange.com/questions/1204396/why-is-the-sum-of-the-rolls-of-two-dices-a-binomial-distribution-what-is-define)