Lernziele
- Sie können erklären, was ein Array ist, und warum man ein solches Konstrukt benötigt
- Sie können neue Arrays erstellen, mit Werten befüllen und die Werte eines Arrays über den Index abrufen
- Sie können mit Hilfe einer Schleife einen Array verarbeiten (z.B. ihn befüllen, auslesen oder ändern)
- Sie können mehrere Entitäten verwalten, indem Sie Eigenschaften in Arrays verwalten (z.B. Koordinaten bei der Animation von mehreren Bällen)
- Sie können Arrays von Objekten bilden und mit diesen arbeiten
- Sie können Arrays so verwenden, dass die Länge flexibel ist
- Sie können zwei-dimensionale Arrays erstellen, befüllen, verwenden
Voraussetzungen
Sie sollten sicher mit Variablen umgehen können Kapitel 2.
Sie sollten sicher mit If-Anweisungen umgehen können Kapitel 3.
Sie sollten sicher mit Schleifen umgehen können Kapitel 4.
Für Abschnitt 6.4 sollten Sie mit Objekten Kapitel 4 umgehen können.
- 23.01.2024: Level zu Aufgaben hinzugefügt
- 09.01.2023: Neues Video Flexible Arrays (6.5)
- 05.10.2021: Lernziele angepasst
- 02.08.2021: Neue Kapitelnummerierung
In diesem Kapitel lernen wir, wie man viele Informationen in einem Konstrukt abspeichert. Zum Beispiel wollen wir in einem Spiel 10 Bälle fliegen lassen und wollen für alle Bälle die x-Koordinate speichern. Wir wollen aber nicht 10 verschiedene Variablen anlegen, weil wir später vielleicht entscheiden, dass wir 100 Bälle brauchen. Oder wir wollen während des Spiels die Anzahl der Bälle verändern. Alles ganz leicht mit Arrays, wie man in diesem Fenster sieht (Aufgabe 6.3b).
Erstmal eine Definition:
Array
Ein Array in einem Computerprogramm ist ein Konstrukt, das mehrere Werte gleichen Typs systematisch mit Hilfe einer einzigen Variablen speichern kann, z.B. mehrere ganze Zahlen oder mehrere Strings.
6.1 Einführung in Arrays
Video: Arrays (10:38)
Array erzeugen
Wenn eine Variable sowas wie ein Becher ist, dann ist ein Array sowas wie ein Becherhalter. Nehmen wir eine Integer-Variable für die x-Position eines Balls oder auch eine Float-Variable oder eine boolesche Variable.
int x; float foo = 42.3; boolean play = true;
Die Variable x
ist nur deklariert, wird aber automatisch mit dem Wert Null gefüllt. Das kann man sich so vorstellen:
Jetzt möchten wir einen Array anlegen, der z.B. gleich fünf x-Positionen speichern kann. Das tun wir in zwei Schritten. Zunächst deklarieren wir eine Variable, die einen Becherhalter enthalten kann. Man beachte, dass der Becherhalter an sich noch nicht existiert!
int[] xarray; // Arrayvariable deklarieren
Ein Array ist ein Objekt (wie PVector oder String).
Die Variable xarray
kann einen Array speichern, ist aber
jetzt noch leer. Wie wir wissen, setzt Processing/Java daher
eine Markierung namens
null
ein:
Jetzt müssen wir noch den Becherhalter erzeugen. Hier müssen wir uns festlegen, wie viele Becher genau das Array halten kann. Stellen Sie sich das Array wie ein Muffin-Backblech vor, da müssen Sie sich bei Herstellung auch entscheiden, wieviele Muffin-Löcher Sie reinstanzen.
Wir nehmen mal 5 Becher:
xarray = new int[5]; // Array mit 5 Elementen erzeugen
Häufig macht man beides in einem Schritt:
int[] xarray = new int[5];
Unseren Becherhalter kann man sich wie ein Gitter vorstellen,
eine Batterie von Behältern. Die Variable
xarray
zeigt jetzt auf dieses Gebilde:
Beachten Sie, dass der Datentyp dieser Variable
int[]
ist, also ein Integer-Array, angedeutet durch
die eckigen Klammern. Die Variable
xarray
kann also
nicht etwa eine einzelne Zahl speichern, sondern eben nur diesen kuriosen
Becherhalter.
Elemente zugreifen
Jetzt haben Sie plötzlich 5 Becher statt nur einen. Wir nennen die Becher auch Array-Elemente. Wie kommen Sie an so ein Element ran? Ganz einfach: die Elemente sind durchnummeriert, und zwar von 0 bis 4. Diese Zahlen nennt man auch Indices bzw. im Singular Index.
Diese fünf Elemente können Sie mit folgender Syntax abrufen:
println(xarray[0]); // Element 0 ausgeben println(xarray[1]); // Element 1 ausgeben println(xarray[2]); println(xarray[3]); println(xarray[4]); // letztes Element ausgeben
Zu Beginn haben Sie da überall Nullen drin, weil jeder einzelne Becher vom Typ Integer ist. Wenn Sie das ändern wollen, schreiben Sie zum Beispiel:
xarray[3] = 42; // Zuweisung
Intern sieht das Array jetzt so aus:
Wenn Sie genau hinschauen, werden Sie feststellen, dass sich
ein einzelnes Element wie
xarray[0]
ganz genau
so verhält wie eine handelsübliche Integer-Variable. Man
muss sich nur an diese eckigen Klammern gewöhnen.
Sie können z.B. auch mit Array-Elementen rechnen:
int result = xarray[0] + xarray[5] - 10;
Größe des Array
Wir haben oben ein Array mit 10 Elementen geschaffen. Diese Zahl
ist eine Eigenschaft des Array-Objekts,
die wir per Punktnotation abrufen können und zwar mit
xarray.length
.
Beispiel:
int[] xarray = new int[555]; println(xarray.length);
555
Beliebter Fehler (Exception)
Der beliebteste Anfängerfehler bei Arrays ist es, nicht zu beachten, dass Informatiker immer bei Null anfangen zu zählen. Ist ja auch merkwürdig. Versuchen Sie mal:
int[] xarray = new int[10]; xarray[10] = 23; // Index 10 existiert nicht!
Processing sagt zu recht: ArrayIndexOutOfBoundsException. Eine 'Exception' (engl. Ausnahme) bedeutet beim Programmieren 'Fehler'. In diesem Fall ist der Fehler, dass das Element 10 nicht existiert. Es existieren nur Elemente mit Namen 0 bis 9.
Kurzschreibweise: Array erzeugen und befüllen
Wenn Sie schnell ein Array erzeugen und gleich mit konkreten Werten befüllen möchten, schreiben Sie:
int[] zahlen = {8, 42, -3, 200};
Dieses Konstrukt erzeugt eine neue Array-Variable
zahlen
der Länge 4 mit den entsprechenden Werten. Die ausführliche Variante wäre:
int[] zahlen = new int[4]; zahlen[0] = 8; zahlen[1] = 42; zahlen[2] = -3; zahlen[3] = 200;
Vorsicht: Die Kurzschreibweise dürfen Sie nur dann verwenden, wenn die Variable deklariert wird, also ganz am Anfang der Lebensdauer einer Array-Variablen. Die Kurzschreibweise ist später nicht mehr erlaubt. Das hier geht nicht:
int[] zahlen = new int[3]; zahlen = { 5, 20, 8 }; // FEHLER! Nur bei Deklaration erlaubt.
Array ausgeben
In Processing können Sie übrigens mit
println(zahlen);
sehr bequem die Inhalte eines Arrays betrachten, die jeweilige Indexzahl wird in Klammern mit ausgegeben:
[0] 8 [1] 42 [2] -3 [3] 200
Diese besondere Art der Ausgabe gibt es nur in Processing, nicht in Java.
Coding Style
Bitte achten Sie darauf, wo Leerzeichen und Zeilenumbrüche gemacht werden, und wo nicht.
int[] zahlen; zahlen = new int[10]; zahlen[2] = zahlen[0] + zahlen[1];
Denken Sie auch daran, Ihren Code mit Bearbeiten > Autoformatierung von Processing korrekt einrücken zu lassen (Tastenkürzel STRG+T bzw. CMD+T).
Fingerübungen
a) Float-Array
Erstellen Sie einen Array vom Typ float der Länge 5. Legen Sie den Array in einer Variablen namens fa
an.
Setzen Sie die Werte des ersten, dritten und letzten Elements auf 10. Geben Sie den gesamten Array auf der Konsole aus.
float[] fa = new float[5]; fa[0] = 10; fa[2] = 10; fa[4] = 10; println(fa);
b) Arrays erstellen per Kurzschreibweise
Legen Sie einen Integer-Array namens a
mit den Werten 0, 8, 15 an. Verwenden Sie die Kurzschreibweise. Geben Sie den Array auf der Konsole aus.
int[] a = {0, 8, 15}; println(a);
Übungsaufgaben
6.1 a) Arrays erstellen Level 11 = easy
2 = relativ leicht
3 = mittel
4 = schwierig
5 = hart
Erstellen Sie je einen Array für
- 5 ganze Zahlen
- 3 Strings
- 4 Kommazahlen
- 3 boolesche Werte
Befüllen Sie anschließend die Arrays mit beliebigen Werten und geben Sie einige Werte einzeln aus, d.h. für ein einzelnes Element eine Print-Anweisung.
Probieren Sie anschließend mit dem ersten Array (ganze Zahlen) die folgenden Befehle aus:
println(foo); print(foo);
print
ausgeben.
Processing ist aber so freundlich, auch einen kompletten Array
bei println
zu akzeptieren und zeigt Ihnen dann alle Wert und
den jeweiligen Index. Das funktioniert allerdings nur bei println
, nicht
bei print
. Bei String-Arrays haben Sie nochmal eine andere Darstellung,
probieren Sie es mal.
6.1 b) Array und Variablen Level 11 = easy
2 = relativ leicht
3 = mittel
4 = schwierig
5 = hart
Erstellen Sie einen int-Array namens foo
mit den Zahlen 5, 45, -10, 20 (in dieser Reihenfolge).
Addieren Sie die ersten zwei Zahlen und legen Sie
das Ergebnis in einer neuen int-Variablen a
ab.
Addieren Sie die letzten zwei Zahlen und legen Sie das
Ergebnis einer neuen int-Variablen b
ab.
Printen sie a
und b
auf die Konsole und überprüfen Sie die Werte.
6.1 c) Array verändern Level 11 = easy
2 = relativ leicht
3 = mittel
4 = schwierig
5 = hart
Erstellen Sie einen int-Array namens bar
mit den Zahlen 2, 4, 6 (in dieser Reihenfolge).
Multiplizieren Sie die ersten zwei Zahlen und legen Sie sie
das Ergebnis in der dritten Zelle des Arrays ab.
Sie sollten also {2, 4, 8} in bar
haben.
Schreiben Sie bar
mit println
auf die Konsole, um dies zu prüfen.
6.1 d) One-Hot-Encoding als Array Level 21 = easy
2 = relativ leicht
3 = mittel
4 = schwierig
5 = hart
Manchmal muss man Zahlen wie 2 oder 4 mit Vektoren darstellen, wobei die Vektoren immer die gleiche Länge haben sollen, z.B. fünf. Man wandelt diese Zahlen dann in Vektoren um, die überall eine Null haben außer an einer einzigen Stelle, wo eine 1 steht. Die Zahl 2 wird zum Beispiel zum Vektor (0 0 1 0 0) und die Zahl 4 zu (0 0 0 0 1). Man nennt die Vektoren dann One-Hot-Encoding, weil eine beliebige Zahl über eine "heiße" Stelle enkodiert wird.
Schreiben Sie Code, wo die gewünschte Zahl in der Variablen z
steht und die Länge des Vektors in n
.
Für den Vektor erstellen Sie einen Array namens oneHot
.
int z = 2; int n = 5; // Hier erstellen Sie den "Vektor" in Form eines Arrays println(oneHot);
Sie sollten sehen:
[0] 0 [1] 0 [2] 1 [3] 0 [4] 0
One-Hot-Encoding benötigt man im Bereich des Deep Learning, um Eingabedaten für Neuronale Netze vorzubereiten.
Zusammenfassung
Ein Array kann mehrere Informationen vom gleichen Typ speichern. Man kann sich einen Array auch als Schrank mit durchnummerierten Fächern vorstellen.
-
Der Datentyp eines Array ist der Typ der enthaltenen Element und dahinter
eckige Klammern, z.B.
int[]
für einen Integer-Array oderString[]
für einen String-Array -
Array mit 5 Fächern erzeugen:
new int[5]
- Elemente sind durchnummeriert, beginnend bei Null. Diese Nummer nennt man Index eines Elements.
-
Zugriff auf ein Element über den Index:
foo[3]
greift auf das 4. Element zu -
Länge des Array
foo
mitfoo.length
. -
Schnelles Erzeugen und Befüllen eines Array:
int[] foo = { 3, 42, -50 };
6.2 Arrays mit Schleifen
Bislang scheinen Arrays nur eine umständliche Art zu sein, schnell viele Variablen zu erzeugen. Ihre volle Kraft entfalten Arrays aber erst im Zusammenspiel mit Schleifen.
Array initialisieren
Wenn Sie einen großen Array erschaffen, möchten Sie die Anfangswerte nicht für jedes Element einzeln setzen. Das Setzen der Anfangswerte nennt man auch Initialisieren.
int[] foo = new int[1000];
Also verwenden Sie eine Schleife, um z.B. alle Werte auf 10 zu setzen:
for (int i = 0; i < 1000; i++) { foo[i] = 10; }
Vielleicht möchten Sie die Elemente auch auf die Werte 100, 110, 120, ... setzen:
for (int i = 0; i < 1000; i++) { foo[i] = 100 + i * 10; }
Oder auf Zufallswerte zwischen 0 und 99:
for (int i = 0; i < 1000; i++) { foo[i] = int(random(100)); }
Arraywerte einsetzen
Schleifen spielen nicht nur beim initialisieren von Arrays eine wichtige Rolle. Wenn Sie z.B. Koordinaten von Rechtecken in zwei Arrays speichern, dann erschaffen und initialisieren Sie zunächst zwei Arrays (mit Zufallswerten) und verwenden dafür eine Schleife.
int[] xa = new int[100]; int[] ya = new int[100]; for (int i = 0; i < 100; i++) { xa[i] = int(random(100)); ya[i] = int(random(100)); }
Dann verwenden Sie zum Zeichnen der Rechtecke ebenfalls eine Schleife:
for (int i = 0; i < 100; i++) { rect(xa[i], ya[i], 30, 30); }
Vielleicht möchten Sie auch alle Werte der zwei Arrays auf der Konsole ausgeben. Auch dazu können Sie eine Schleife verwenden:
for (int i = 0; i < 100; i++) { println("x: " + xa[i] + ", y: " + ya[i]); }
In diesem speziellen Fall könnte man das Zeichnen und das Print auch in die obere Schleifen mit einbauen. Bei einer Animation findet das Initialisieren aber oft im setup
statt und das Zeichnen in draw
. Wir sehen dazu gleich ein Beispiel.
Beispiel: Animation vieler Bälle
Jetzt ein praktisches Beispiel: Wir lassen drei Bälle über den Bildschirm fliegen. Dazu verwenden wir einen Array für die x-Koordinate der drei Bälle. Zunächst mal ohne Schleifen.
int[] xarray = new int[3]; // erzeugen void setup() { // initialisieren xarray[0] = 0; xarray[1] = 20; xarray[2] = 40; } void draw() { background(255); // Werte verwenden ellipse(xarray[0], 50, 10, 10); ellipse(xarray[1], 50, 10, 10); ellipse(xarray[2], 50, 10, 10); // Werte hochzählen xarray[0]++; xarray[1]++; xarray[2]++; }
Sie haben jetzt drei Bälle und ein Array mit drei Elementen. Sie hätten genauso schreiben können:
int x1; int x2; int x3; void setup() { x1 = 0; x2 = 20; x3 = 40; } void draw() { background(255); ellipse(x1, 50, 10, 10); ellipse(x2, 50, 10, 10); ellipse(x3, 50, 10, 10); x1++; x2++; x3++; }
Der Vorteil der Array-Lösung? Sie können die einzelnen Elemente mit Hilfe einer Schleife durchlaufen. Nehmen wir an, Sie wollen ein Array mit lauter 5en füllen:
int[] fuenfer = new int[10];
Das müsste man so machen:
fuenfer[0] = 5; fuenfer[1] = 5; fuenfer[2] = 5; fuenfer[3] = 5; fuenfer[4] = 5; fuenfer[5] = 5; fuenfer[6] = 5; fuenfer[7] = 5; fuenfer[8] = 5; fuenfer[9] = 5;
Wir sehen aber: alles bleibt gleich, bis auf den Index (die Zahl in Klammern). Also könnten wir diese Zahl durch eine Laufvariable in einer Schleife ersetzen:
for (int i = 0; i < 10; i++) { fuenfer[i] = 5; }
Sehen wir uns die Entwicklung der Dinge in der Schleife an. Es wird
die Laufvariable
i
rundenweise hochgezählt. Bevor
der Code ausgeführt wird, wird noch die Schleifenbedingung
i < 10
geprüft. Ist diese
false
, ist die Schleife fertig.
In unserem Ball-Beispiel von oben kann man zwei Schleifen einfügen.
In der ersten Schleife wird die x-Startposition mit
i * 20
berechnet. In drei Durchläufen ergibt sich jeweils: 0 * 20, 1 * 20 und 2 * 20,
also 0, 20, 40.
int[] xarray = new int[3]; void setup() { for (int i = 0; i < 3; i++) { xarray[i] = i * 20; // berechne x-Startposition } } void draw() { background(255); for (int i = 0; i < 3; i++) { ellipse(xarray[i], 50, 10, 10); // zeichnen xarray[i]++; // hochzählen } }
Diese Lösung ist nicht nur kürzer, sondern auch mächtiger. Sie können nämlich mit einem Fingerschnipp die Anzahl der Bälle erhöhen, z.B. auf 5. Dazu müssen Sie an drei Stellen im Code die 3 durch 5 ersetzen.
Größe des Arrays verwenden
Die Lösung oben lässt sich verbessern, indem man in die For-Schleife
die Größe des Arrays mit
xarray.length
einsetzt, zum Beispiel in der unteren Schleife:
for (int i = 0; i < xarray.length; i++) { ellipse(xarray[i], 50, 10, 10); // zeichnen xarray[i]++; // hochzählen }
Wenn Sie dies für beide Schleifen tun, dann müssen Sie nur noch eine Stelle ändern, um die Anzahl der Bälle anzupassen: ganz oben.
// optimale Lösung int[] xarray = new int[3]; void setup() { for (int i = 0; i < xarray.length; i++) { xarray[i] = i * 20; } } void draw() { background(255); for (int i = 0; i < xarray.length; i++) { ellipse(xarray[i], 50, 10, 10); xarray[i]++; } }
Probieren Sie es aus: setzen Sie bei
int[3]
oben eine andere Zahl ein.
Versuchen Sie 2 oder 10 oder nur eine 1. Alles kein Problem.
Fingerübungen
a) Array ausgeben
Gegeben sei ein Array:
float[] fa = { 1.5, 3.5, 5.5, 7.5 };
Schreiben Sie alle Zahlen zeilenweise auf die Konsole.
for (int i = 0; i < fa.length; i++) { println(fa[i]); }
b) Array befüllen
Erzeugen Sie ein Integer-Array a
der Länge 10 mit den Werten 0, 1, 2, ... , 9. Nutzen Sie dazu eine For-Schleife.
Achten Sie darauf, dass sich die For-Schleife automatisch an die Größe des Arrays anpasst.
int[] a = new int[10]; for (int i = 0; i < a.length; i++) { a[i] = i; } println(a);
Übungsaufgaben
In den folgenden Aufgaben sollte immer eine For-Schleife zum Einsatz kommen.
6.2 a) Befüllen Level 21 = easy
2 = relativ leicht
3 = mittel
4 = schwierig
5 = hart
Erstellen Sie einen Array für 10 ganze Zahlen und befüllen Sie die Elemente mit 1, 2, ..., 10.
Ihr Programm soll so allgemein geschrieben sein, dass Sie auch Arrays mit 20 oder 100 Elementen befüllen können.
Varianten: Befüllen Sie den Array mit- -10, -9, ..., -2, -1
- 2, 4, 6, ..., 20
- 100, 110, 120, ..., 190
length
, um Ihre Schleife unabhängig von der konkreten Länge des Arrays zu machen. Falls Ihr Array foo
heißt, verwenden Sie foo.length
für die Länge.
6.2 b) Befüllen à la Fibonacci Level 31 = easy
2 = relativ leicht
3 = mittel
4 = schwierig
5 = hart
Befüllen Sie einen Array der Länge 10 mit den Fibonacci-Zahlen: 1, 1, 2, 3, 5, 8, 13, ...
Beachten Sie, dass diese Variante etwas anders funktioniert (einfacher!) als die Aufgabe, mit Hilfe einer Schleife Fibonacci-Zahlen zu erzeugen. Hier können Sie auf die Vorgängerzahlen im Array zugreifen!
6.2 c) Befüllen von zwei Arrays Level 21 = easy
2 = relativ leicht
3 = mittel
4 = schwierig
5 = hart
Befüllen Sie zwei Arrays gleichzeitig in einer Schleife. Beide Arrays haben Länge 10. Das eine Array wird mit 1, 2, 3, ... befüllt, das zweite Array mit -10, -9, -8, ...
6.2 d) Elemente verdoppeln Level 21 = easy
2 = relativ leicht
3 = mittel
4 = schwierig
5 = hart
Verändern Sie den Array dahingehend, dass jedes Element verdoppelt wird.
int[] bla = { 2, 1, 3, 5 }; // Hier Code schreiben println(bla);
Sie sollten das hier auf der Konsole sehen:
[0] 4 [1] 2 [2] 6 [3] 10
6.2 e) Summe Level 31 = easy
2 = relativ leicht
3 = mittel
4 = schwierig
5 = hart
Berechnen Sie die Summe von allen Elementen
des Array und geben Sie diese auf der Konsole aus.
Der Code sollte ohne weitere Änderungen funktionieren, wenn Sie Zahlen zu foo
hinzufügen oder entfernen.
int[] foo = { 22, -10, 8, 10 }; // Hier Code schreiben
Sie sollten das hier auf der Konsole sehen:
30
6.2 f) Array filtern Level 21 = easy
2 = relativ leicht
3 = mittel
4 = schwierig
5 = hart
Gegeben sei Array a
. Drucken Sie alle negativen Elemente untereinander auf der Konsole aus.
int[] a = { 1, -2, -25, 6, -3, 5 };
if
.
6.2 g) Mehrere Arrays addieren Level 21 = easy
2 = relativ leicht
3 = mittel
4 = schwierig
5 = hart
Gegeben sind zwei Arrays a
und b
und ein leerer Array c
. Die Arrays sind gleich lang.
Belegen Sie Array c
so, dass im Element c[0]
die Summe von a[0]
und b[0]
steht und entsprechend für die anderen Elemente von c
.
int[] a = { 1, 2, 25, 6 }; int[] b = { 9, 18, 5, 34 }; int[] c = new int[4]; // Hier Code schreiben println(c);
Sie sollten das hier auf der Konsole sehen:
[0] 10 [1] 20 [2] 30 [3] 40
Es ist immer gut, die Lösung zu testen, indem man andere Werte einsetzt. Hier könnten Sie auch die Länge der Arrays verändern (natürlich müssen alle gleich lang bleiben).
6.2 h) Arrays zusammenfügen Level 31 = easy
2 = relativ leicht
3 = mittel
4 = schwierig
5 = hart
Gegeben sind zwei Arrays a
und b
. Erzeugen Sie einen neuen
Array c
, der so lang ist wie a
und b
zusammengenommen und
auch die Werte von a
und b
(in dieser Reihenfolge) enthält.
int[] a = { 1, 2, 25 }; int[] b = { 9, 18 }; // Hier Code schreiben println(c);
Sie sollten das hier auf der Konsole sehen:
[0] 1 [1] 2 [2] 25 [3] 9 [4] 18
Verwenden Sie nicht die Processing-Funktionen concat
oder splice
.
Wichtig:
Ihr Code sollte auch funktionieren, wenn Sie bei a
oder b
Elemente hinzufügen oder entfernen. Testen Sie das!
Zerlegen Sie das Problem in zwei Schritte. In Schritt 1 befüllen Sie den ersten Teil von c
mit den Werten von a
. In Schritt 2 füllen Sie den zweiten Teil von c
mit den Werten von b
.
Jeden Schritt lösen Sie mit einer eigenen For-Schleife. Schritt 1 ist leicht, denn die Indexzahlen von a
und c
sind gleich (c[0] bekommt Wert von a[0] usw.). Schritt 2 erfordert eine kleine Änderung. Wie lautet die Indexzahl in c
für den ersten Wert von b
?
6.2 i) Array rückwärts Level 31 = easy
2 = relativ leicht
3 = mittel
4 = schwierig
5 = hart
Gegeben sei ein Array:
int[] foo = { 1, 2, 3, 4 };
Erstellen Sie einen neuen Array bar
, wo die Elemente in umgekehrter Reihenfolge abgelegt sind. Wenn Sie bar
ausgeben, sehen Sie also:
[0] 4 [1] 3 [2] 2 [3] 1
Verwenden Sie nicht die Processing-Funktion reverse
.
Wie immer soll Ihr Code auch für andere Arrays funktionieren.
i
durch 0, 1, 2, 3 und befüllen den neuen Array bar
.
Welchen Wert weisen Sie bar[i]
zu? Notieren Sie das per Hand. Es geht um einen Zusammenhang zwischen den Indexzahlen von bar
und foo
.
6.2 j) Elemente verschieben Level 31 = easy
2 = relativ leicht
3 = mittel
4 = schwierig
5 = hart
Gegeben sei ein Array:
int[] foo = { 10, 20, 30, 40, 50 };
Verschieben Sie alle Elemente ab Index 1 um eine Stelle nach rechts. Als Ergebnis sollte hinter das folgende in foo stehen:
[0] 10 [1] 10 [2] 20 [3] 30 [4] 40
6.2 k) Nachbarn addieren Level 31 = easy
2 = relativ leicht
3 = mittel
4 = schwierig
5 = hart
Gegeben sei ein Array mit einer geraden Anzahl von Elementen:
int[] foo = { 1, 2, 3, 4, 5, 6 };
Erstellen Sie einen neuen Array bar
, das halb so lang ist wie foo
und wo jeweils zwei benachbarte Elemente von foo
addiert wurden, also hier 1+2 und 3+4 und 5+6. Wenn Sie bar
ausgeben, sehen Sie also:
[0] 3 [1] 7 [2] 11
6.2 l) Boolesche Operationen Level 41 = easy
2 = relativ leicht
3 = mittel
4 = schwierig
5 = hart
Abstrakt geht es um die Frage, wie Sie
bei einer Menge von N Wahrheitswerten herausfinden,
ob mindestens ein Wert true
ist (entspricht
ODER) bzw. ob alle Werte true
sind
(entspricht UND). Die Werte liegen in einem Array vor.
Vorbereitung
Zur Vorbereitung der Aufgabe erzeugen Sie einen Array "infiziert" mit zehn Elementen. Jeder Eintrag soll mit einer Wahrscheinlichkeit von 5% true sein.
boolean[] infiziert = new boolean[10]; for (int i = 0; i < infiziert.length; i++) { // Ihr Code } println(infiziert); // Kontrolle
true
zu setzen?
Teil 1
Die erste Aufgabe ist jetzt festzustellen, ob mindestens eine Person infiziert ist von den 10. Sie sollen dies mit Hilfe einer Schleife lösen, damit Ihre Lösung auch für sehr große Arrays funktioniert. Geben Sie also "mindestens eine/r infiziert" oder "keiner infiziert" aus als auch den kompletten Array aus, um zu sehen, ob Ihr Programm korrekt arbeitet.
true
sein, wenn mindestens eine/r infiziert war.
Teil 2
Die zweite Aufgabe ist festzustellen, ob alle infiziert sind. Um dies zu testen, setzen Sie die Wahrscheinlichkeit, dass eine/r infiziert ist, auf 95% (siehe Vorbereitung oben).
Geben Sie hier "alle infiziert" oder "nicht alle infiziert" aus.
Zusammenfassung
Arrays und For-Schleifen sind die perfekten Partner. Mit einer For-Schleife können Sie ganz leicht einen kompletten Array befüllen (z.B. alle Elemente mit der Zahl 0 oder mit einer Zufallszahl).
int[] xarray = new int[3]; for (int i = 0; i < 3; i++) { xarray[i] = 0; }
Außerdem können Sie mit einer Schleife alle Elemente eines Arrays abrufen, z.B. um Dinge zu zeichnen (wenn ein Array etwa die x-Koordinate enthält).
for (int i = 0; i < 3; i++) { ellipse(xarray[i], 50, 10, 10); }
Arrays sind eigentlich Objekte. Mit der Objekteigenschaft
length
können Sie die Länge eines Arrays herausfinden.
Das nutzen wir in allen For-Schleifen, um den Code möglichst flexibel
zu halten (d.h. der Code funktioniert auch dann, wenn die Länge sich
ändert).
for (int i = 0; i < xarray.length; i++) { ellipse(xarray[i], 50, 10, 10); }
6.3 Eigenschaften in Arrays speichern
Personen repräsentieren
Stellen Sie sich vor, Sie möchten mehrere Dinge speichern, zum Beispiel eine Person, aber diese Dinge haben mehrere Eigenschaften. Eine Person hat einen Namen, ein Alter, ein Geschlecht. In einem Array können Sie aber nur eine Eigenschaft speichern.
Die Lösung ist, für jede Eigenschaft ein eigenes Array zu verwenden. Ein String-Array für die Namen der Personen und ein int-Array für die Altersangaben:
String[] namen; int[] alter;
Jetzt können wir drei Personen speichern:
String[] namen = { "Max Schmidt", "Lisa Marx", "Robin Meier" }; int[] alter = { 33, 28, 12 };
Das Bindeglied zwischen den Arrays ist die Indexzahl:
- Index 0 steht für "Max Schmidt" und für Alter 33
- Index 1 für "Lisa Marx" und Alter 28
- Index 2 für "Robin Meier" und Alter 12
String[] namen = { "Max Schmidt", "Lisa Marx", "Robin Meier" }; int[] alter = { 33, 28, 12 }; boolean[] weiblich = { false, true, false };
Wie können wir diese Darstellung nutzen? Wir könnten alle Personen mit allen Eigenschaften ausdrucken. Dabei benutzen wir die Information zum Geschlecht, um die richtige Anrede zu wählen.
for (int i = 0; i < namen.length; i++) { if (weiblich[i]) { print("Frau "); } else { print("Herr "); } println(namen[i] + ", " + alter[i] + " Jahre alt"); }
Die Ausgabe ist:
Herr Max Schmidt, 33 Jahre alt Frau Lisa Marx, 28 Jahre alt Herr Robin Meier, 12 Jahre alt
Grafische Objekte repräsentieren
Arrays bieten sich auch an, um mehrere grafische Objekte
und deren Eigenschaften zu speichern.
Wollen wir die x/y-Koordinaten von Rechtecken speichern,
verwenden wir zwei Arrays
xpos
und
ypos
.
Für uns ist klar: für jeden Index gibt es ein Rechteck und die
beiden Elemente, z.B.
xpos[3]
und
ypos[3]
beinhalten die Koordinaten des 4. Rechtecks (nicht die Null vergessen!).
// 100 Rechtecke mit je zwei Eigenschaften (xpos, ypos), // die über die Cursortasten verändert werden können int[] xpos = new int[100]; int[] ypos = new int[100]; void setup() { for (int i = 0; i < xpos.length; i++) { xpos[i] = (int)random(0, width); ypos[i] = (int)random(0, height); } } void draw() { background(0); fill(255); for (int i = 0; i < xpos.length; i++) { rect(xpos[i], ypos[i], 10, 10); } } void keyPressed() { if (keyCode == LEFT) { for (int i = 0; i < xpos.length; i++) { xpos[i]--; } } if (keyCode == RIGHT) { for (int i = 0; i < xpos.length; i++) { xpos[i]++; } } if (key == ' ') { for (int i = 0; i < xpos.length; i++) { xpos[i] = (int)random(0, width); ypos[i] = (int)random(0, height); } } }
Interaktives Feld:(erst auf das graue Feld klicken, dann Cursortasten)
Im oberen Beispiel haben wir 100 Objekte mit je zwei Eigenschaften (xpos und ypos). Jetzt nehmen wir eine dritte Eigenschaft hinzu: die Farbe.
// 100 Rechtecke mit je drei Eigenschaften // Die Cursortasten ändern jetzt die jeweilige Graustufe int[] xpos = new int[100]; int[] ypos = new int[100]; int[] farbe = new int[100]; void setup() { for (int i = 0; i < xpos.length; i++) { xpos[i] = (int)random(0, width); ypos[i] = (int)random(0, height); farbe[i] = (int)random(0, 256); } } void draw() { background(0); for (int i = 0; i < xpos.length; i++) { fill(farbe[i]); rect(xpos[i], ypos[i], 10, 10); } } void keyPressed() { if (keyCode == LEFT) { for (int i = 0; i < xpos.length; i++) { farbe[i] -= 5; farbe[i] = constrain(farbe[i], 0, 255); } } if (keyCode == RIGHT) { for (int i = 0; i < xpos.length; i++) { farbe[i] += 5; farbe[i] = constrain(farbe[i], 0, 255); } } }
Die Farbe muss mit der Funktion
constrain
im Wertebereich 0..255 gehalten werden.
Übungsaufgaben
Die Aufgaben (b) - (e) bauen aufeinander auf.
6.3 a) Personen filtern Level 31 = easy
2 = relativ leicht
3 = mittel
4 = schwierig
5 = hart
Sie haben eine Anzahl Personen wie oben beschrieben in drei Arrays repräsentiert:
String[] namen = { "Max Schmidt", "Lisa Marx", "Robin Meier", "Lara Huber", "Anna Groß", "Heribert Lehmann", "Harry Potter", "Obi-wan Kenobi", "Julia Kron" }; int[] alter = { 33, 28, 12, 22, 23, 64, 16, 102, 18 }; boolean[] weiblich = { false, true, false, true, true, false, false, false, true };
Listen Sie mit Hilfe einer Schleife nur die Frauen auf und zwar wie folgt:
Frau Lisa Marx Frau Lara Huber Frau Anna Groß Frau Julia Kron
Jetzt sollen Sie zählen! Verwenden Sie eine Schleife und (mehrere) Zählervariablen, um folgende Personengruppen zu zählen:
- Alle Frauen
- Alle Personen unter 40
- Alle Männer über 30
Geben Sie die drei Zahlen auf der Konsole aus.
6.3 b) Viele Bälle Level 41 = easy
2 = relativ leicht
3 = mittel
4 = schwierig
5 = hart
Lassen Sie 10 Bälle in unterschiedlichen Geschwindigkeiten (zufällig) über den Bildschirm fliegen. Geben Sie jedem Ball eine eigene Farbe.
Verwenden Sie random
in setup
, um die x/y-Koordinaten
zufällig zu setzen. Das gleiche gilt für die Geschwindigkeit.
Für die Farbe können Sie den Datentyp color
verwenden.
Mit der Funktion color(r, g, b) können Sie dann eine Farbe erzeugen.
Variante: Durch kleine Änderungen können Sie das obige Konzept zum Generieren interessanter Grafiken nutzen:
(Anklicken, um den Bildschirm zu löschen.)
6.3 c) Ausschalten Level 41 = easy
2 = relativ leicht
3 = mittel
4 = schwierig
5 = hart
Bauen Sie ein, dass man jeden einzelnen Ball "ausschalten" kann. Verwenden Sie dazu einen Array von booleans. Bauen Sie ein, dass man über die Zifferntasten 0, ..., 9 die entsprechenden Bälle ein- und ausschalten kann. Sie können die Bälle entweder ganz verschwinden lassen oder auch nur die Bewegung rausnehmen, d.h. der Ball bleibt stehen. Es reicht jedoch nicht, nur die Geschwindigkeit auf 0 zu setzen, dann können Sie den Ball nicht mehr reaktiveren. Deshalb: Array von booleans.
keyCode
steht immer der Code der zuletzt gedrückten Taste. Finden Sie zunächst heraus, welche Codes die Tasten 1, 2, 3 etc. haben, indem Sie sich den Code mit println
ausgeben lassen.
6.3 d) Killerball Level 41 = easy
2 = relativ leicht
3 = mittel
4 = schwierig
5 = hart
Führen Sie einen neuen Ball ein, der nicht im Array ist und den Sie mit den Cursortasten steuern können. Sobald dieser Spielball einen der anderen Bälle berührt, verschwindet der andere Ball.
Verwenden Sie einen Array von booleans um das "Verschwinden" zu realisieren. Eine "true" bedeutet, der Ball mit entsprechendem Index ist noch im Spiel. Bei einer Kollision setzen Sie einfach den entsprechenden Wert auf "false".
Wie Sie die Kollision erkennen, steht in Kapitel 3.6.
6.3 e) Gewinnen Level 41 = easy
2 = relativ leicht
3 = mittel
4 = schwierig
5 = hart
Wenn alle Bälle fort sind, gewinnen Sie. In diesem Fall setzen Sie ein "Gewonnen!" direkt auf die Screen (vor schwarzem Hintergrund).
Sie sollten das Ein- und Ausschlalten der Bälle über einen Array von Booleans regeln. Um zu testen, ob alle Elemente false
sind, verwenden Sie eine Schleife. Siehe auch die letzte Aufgabe in 8.1.
Führen Sie eine neue boolesche Variable (z.B. gameOver) ein, die Sie in draw benutzen, um zu unterscheiden, ob Sie das "Spiel" darstellen oder den Text "Gewonnen". Um die Funktionsweise der Variable zu testen, setzen Sie die Variable auf true (oder false) und starten Sie Ihr Programm. Wenn die Variable funktioniert, implementieren Sie den Test des Boolean-Arrays und setzen dann im Programm die gameOver-Variable.
Zusammenfassung
Ein Array kann eine Serie von Daten eines Typs speichern, z.B. ganze Zahlen oder Strings.
Wenn Sie Daten für eine Reihe von Entitäten haben, seien es Personen oder grafische Objekte, können Sie die verschiedenen Aspekte dieser Entitäten (Name, Alter, Koordinaten etc.) in verschiedenen Arrays speichern. Der Zusammenhalt dieser Daten wird durch die Indexzahl gewährleistet: eine Indexzahl repräsentiert eine Entität (Person oder Objekt).
Wenn wir zum Beispiel drei Personen mit Name und Alter speichern wollen, können wir das mit zwei Arrays tun:
String[] namen = { "Max Schmidt", "Lisa Marx", "Robin Meier" }; int[] alter = { 33, 28, 12 };
Zum Ausgeben der Personen verwenden Sie eine Schleife:
for (int i = 0; i < namen.length; i++) { println(namen[i] + ", " + alter[i] + " Jahre"); }
6.4 Objekte in Arrays speichern
Natürlich können Sie auch Objekte wie Vektoren oder Bilder in Arrays speichern. Dazu verwenden Sie einfach den Klassennamen (PVector) als Typ und versehen ihn mit eckigen Klammern.
PVector[] spaceships = new PVector[5];
Wichtig ist hier, dass das Array noch keine Objekte enthält. Es wurde noch kein new verwendet, also existieren auch keine Objekte im Speicher.
Schauen Sie sich z.B. das Element 0 als ganzes an, sehen Sie auch das "null":
println(spaceships[0]);
null
Sollten Sie auf die Idee kommen, einen Wert abgreifen zu wollen, werden Sie mit der Fehlermeldung NullPointerException bestraft:
println(spaceships[0].x); // NullPointerException
Das heißt, Sie müssen erst einmal durchs komplette Array laufen und Objekte erzeugen. Zum Beispiel mit (0,0)-Vektoren:
for (int i = 0; i < spaceships.length; i++) { spaceships[i] = new PVector(); }
Jetzt haben Sie den Speicher mit Objekten bevölkert und in jede Arrayzelle eine Referenz hinterlegt.
Wenn wir einen Objekt-Array erzeugen, gibt es danach noch keine Objekte. Wir müssen jedes einzelne Objekt mit new erschaffen.
Sie können natürlich auch Zufallswerte verwenden:
for (int i = 0; i < spaceships.length; i++) { float x = random(100); float y = random(100); spaceships[i] = new PVector(x, y); }
Auch der Zugriff auf die einzelnen Zellen des Arrays findet über die eckigen Klammern und den Index statt:
for (int i = 0; i < spaceships.length; i++) { rect(spaceships[i].x, spaceships[i].y, 20, 20); }
Fingerübungen
a) Vektorarray 1
Erstellen Sie einen Array mit fünf Vektor-Objekten. Die fünf Vektoren sollen die Werte (1,1), (2,2) usw. haben.
Verwenden Sie eine Schleife.
PVector[] va = new PVector[5]; for (int i = 0; i < va.length; i++) { va[i] = new PVector(i+1, i+1); } println(va);
b) Vektorarray 2
Erstellen Sie mit Hilfe einer Schleife einen Array von fünf Vektor-Objekten mit Werten (10, 10), (20, 20), (30, 30), (40, 40) und (50, 50).
Zeichnen Sie mit einer zweiten Schleife - unter Verwendung der Vektoren - Kreise mit Durchmesser 20 an den fünf Koordinaten.
PVector[] va = new PVector[5]; for (int i = 0; i < va.length; i++) { va[i] = new PVector((i+1)*10, (i+1)*10); } for (int i = 0; i < va.length; i++) { ellipse(va[i].x, va[i].y, 20, 20); }
Übungsaufgaben
6.4 a) Bälle mit Vektoren Level 21 = easy
2 = relativ leicht
3 = mittel
4 = schwierig
5 = hart
Lassen Sie viele Bälle fliegen. Verwenden Sie dazu zwei Arrays: position
und speed
. Die Arrayelemente sollen vom Typ PVector
sein.
Schauen Sie im Kapitel über Objekte nach, wie Position und Speed addiert werden.
6.4 b) Teleprompter Level 21 = easy
2 = relativ leicht
3 = mittel
4 = schwierig
5 = hart
Speichern Sie einen Text wortweise in einem Array von Strings. Auf dem Grafikbildschirm sieht man das erste Wort in der Mitte.
String[] woerter = { "Ich", "bin", "ein", "Text"};
Wenn man auf die Cursor-rechts-Taste drückt, sieht man statt des ersten Wortes das nächste Wort (wieder in der Mitte). Wenn man auf die Cursor-links-Taste drückt, erscheint das vorige Wort.
Achten Sie darauf, dass Sie nicht "aus dem Array rauslaufen". Processing wird sich dann mit einem Fehler zu Wort melden.
6.4 c) Fliegende Bilder Level 31 = easy
2 = relativ leicht
3 = mittel
4 = schwierig
5 = hart
Statt Kreisen lassen Sie jetzt Bilder fliegen, z.B. Asteroiden, Strandbälle, Angry Birds...
Verwenden Sie dazu den Code aus (a) und verwenden Sie einen Array von PImage-Objekten (siehe Kapitel 4, Abschnitt 4.3)
6.5 Flexible Arrays
Video: Flexible Arrays (7:34)
Arrays haben einen großen Nachteil: Die Länge muss zu Beginn festgelegt werden. Jetzt stellen Sie sich vor, Sie möchten während des Programmlaufs neue "Objekte" zu Ihrem Array hinzufügen (man stelle sich vor: ein Adressbuch und neue Adressen oder ein Spiel mit laufend neuen Asteroiden und sonstigen Objekten). Wie macht man das?
Die Grundidee ist: Wir erzeugen einen Array, der wesentlich größer ist, als wir zunächst brauchen, und verwenden nur einen Teil davon. Nehmen wir an, wir möchten uns Punkte merken. Dann speichern wir x- und y-Koordinate in zwei Arrays. Zu Beginn möchten wir uns nur zwei Punkte merken, aber wir erzeugen dennoch Arrays der Länge 100:
int[] punktX = new int[100]; int[] punktY = new int[100]; void setup() { punktX[0] = 20; punktY[0] = 20; punktX[1] = 40; punktY[1] = 40; punktX[2] = 60; punktY[2] = 60; }
Da wir nicht wissen, wie viele Elemente dieser zwei Arrays wirklich "sinnvoll" verwendet werden, können wir keine Schleife definieren, um die sinnvoll gefüllten Elemente für das Zeichnen zu verwenden. Die Lösung ist, eine neue Variable einzuführen, die angibt, wie weit das Array befüllt ist. In unserem Fall wäre die "Länge" gleich 3.
int[] punktX = new int[100]; int[] punktY = new int[100]; int num = 3;
Jetzt können wir eine Zeichenroutine einführen, die auf num
basiert:
void draw() { for (int i= 0; i < num; i++) { ellipse(punktX[i], punktY[i], 10, 10); } }
Was ist damit gewonnen? Sie können zum Beispiel per Mausklick neue Kreise hinzufügen:
int[] punktX = new int[100]; int[] punktY = new int[100]; int num = 3; void setup() { punktX[0] = 20; punktY[0] = 20; punktX[1] = 40; punktY[1] = 40; punktX[2] = 60; punktY[2] = 60; } void draw() { for (int i= 0; i < num; i++) { ellipse(punktX[i], punktY[i], 10, 10); } } void mousePressed() { punktX[num] = int(random(0, width)); punktY[num] = int(random(0, height)); num++; }
Zu beachten ist, dass num
immer eins höher ist als der aktuell verwendete Index, da es sich um die Länge unseres verwendeten Bereichs im Array handelt. Außerdem führt der obige Code zu einem Fehler, wenn mehr als 100 Punkte erreicht sind. Wie können Sie verhindern, dass der Fehler auftritt?
Sie können übrigens auch Bälle wieder entfernen. Dazu müssen Sie lediglich num
um eins verringern. Probieren Sie es doch einmal aus, z.B. indem Sie beim Druck auf eine Tastaturtaste einen Ball entfernen. Auch hier lauert ein Fehler! Wann bekommen Sie hier ein Problem und wie verhindern Sie es?
Übungsaufgaben
6.5 a) Punkte und Linien Level 41 = easy
2 = relativ leicht
3 = mittel
4 = schwierig
5 = hart
Schreiben Sie ein Programm, wo bei jedem Mausklick ein Punkt an der Stelle der aktuellen Mausposition erzeugt wird. Beim nächsten Klick wird wieder ein Punkt erzeugt und eine Linie zwischen den Punkten gezogen.
Interaktives Feld:(mit der Maus in das Feld klicken)
Hinweis: Lösen Sie die Aufgabe mit Hilfe von flexiblen Arrays wie oben beschrieben (für jeweils x und y). Sie können alternativ auch einen Array von PVector-Objekten benutzen.
Zusatzaufgabe 1: Wenn Sie auf die Backspace-Taste (oder eine andere) drücken, soll der zuletzt erzeugte Punkt wieder verschwinden.
Zusatzaufgabe 2: Erweitern Sie Ihren Code so, dass Sie mit Hilfe der Cursortasten die gesamten gezeichnete Figur pixelweise nach oben/unten/rechts/links verschieben können.
6.5 b) Punkte löschen Level 41 = easy
2 = relativ leicht
3 = mittel
4 = schwierig
5 = hart
Erweitern Sie das obere Programm wie folgt: Wenn Sie auf einen bereits gezeichneten Punkt klicken, dann soll dieser Punkt verschwinden. Die Linie verbinden sich anschließend mit den beiden Nachbarpunkten.
Dazu müssen Sie die Teilaufgabe lösen, wie Sie aus einem Array ein beliebiges Element löschen - denn an der Stelle des gelöschten Elements darf natürlich keine "Lücke" bleiben.
6.5 c) Skalieren Level 51 = easy
2 = relativ leicht
3 = mittel
4 = schwierig
5 = hart
Binden Sie die die +/- Tasten an eine Zoomfunktion. Wenn Sie auf + drücken, vergrößert sich das Gesamtgebilde. Der Ausgangspunkt für die Vergrößerung ist der Bildschirmmittelpunkt. Sie benötigen dafür ein wenig Vektorrechnung (müssen aber nicht notwendigerweise PVector-Objekte verwenden).
6.6 Zweidimensionale Arrays
In einem Array kann man wunderbar eine Reihe von Zahlen (oder Strings) speichern. Die Daten werden, wie wir gesehen haben, mit Indexzahlen angesprochen. Jetzt kommt es oft vor, dass man Zahlen (oder Strings) in einer Art Tabelle speichern möchte. In der Mathematik nennt man das auch eine Matrix, im Alltag kennen Sie Tabellenkalkulationsprogramme wie Excel. Dort werden die Elemente nicht mit einer, sondern mit zwei Indexzahlen angesprochen, z.B. mit Zeilennummer und Spaltennummer.
Beispiele für 2-dimensionale Strukturen:
- Eine Tabelle, z.B. in einem Tabellenkalkulationsprogramm
- Ein Spielfeld wie ein Schachbrett oder das Spielfeld bei PacMan
- Ein Graustufen-Bild mit z.B. 2000x3000 Pixeln
Zu beachten ist lediglich, dass auch in einem 2-dimensionalen Array alle Element vom gleichen Typ sein müssen, also z.B. nur ganze Zahlen, nur Booleans oder nur Strings.
Einfache Arrays
Schauen wir uns einen einfachen Zahlenarray an. Den würden wir wie folgt herstellen:
int[] a = new int[5];
Zu Beginn ist er mit Nullen gefüllt. Das können wir uns so anschauen:
for (int i = 0; i < a.length; i++) { print(a[i] + " "); }
0 0 0 0 0
Wir müssen zwischen den Inhalten und den Indexzahlen unterscheiden. Schematisch sieht das so aus:
Wir haben eine Kurzschreibweise für das schnelle Erstellen von befüllten Arrays kennen gelernt:
int[] a = {10, 7, 0, -5, 33};
Nochmal die schematische Sicht:
Außerdem eine Kurzschreibweise für die Ausgabe eines Arrays:
println(a);
[0] 10 [1] 7 [2] 0 [3] -5 [4] 33
Die zweite Dimension
Jetzt wollen wir uns einen Array mit zwei Dimensionen anschauen. Wenn wir uns den einfachen Array als eine Zeile vorstellen, wollen wir jetzt zwei Zeilen haben.
Array erzeugen
Wir erzeugen den Array so:
int[][] b = new int[2][5];
Der 2-dimensionale Array hat zwei Indices. Man kann sich vorstellen, dass der erste Index (die erste Klammer) ein "normaler" Array der Länge 2 ist:
Entsprechend erhalten Sie die Länge 2, wenn Sie nach der Länge von b
fragen:
println(b.length);
2
In jedem Element enthält der Array jeweils einen weiteren Array der Länge 5, wo die Elemente mit dem zweiten Index (die zweite Klammer) angesprochen werden.
Entsprechend erhalten Sie die Länge 5 für sowohl b[0]
als auch b[1]
:
println(b[0].length); println(b[1].length);
5 5
2-dimensionaler Array als Tabelle
Eine pragmatischere Vorstellung ist die einer Tabelle mit 2 Zeilen und 5 Spalten. Die beiden Klammern enthalten dann unsere "Koordinaten" in dieser Tabelle, wobei es Konvention ist, die erste Koordinate als Zeile, die zweite Koordinate als Spalte aufzufassen. Sie können jetzt mit folgender Notation auf einzelne Elemente zugreifen:
b[0][0] = 4; b[1][4] = 2;
In unserem Schema ändern wir entsprechend die Werte:
Array mit Schleifen durchlaufen
Wenn wir mit Schleifen alle Elemente durchlaufen möchten, benötigen wir zwei verschachtelte Schleifen. Eine Schleife für das Durchlaufen aller Zeilen (äußere Schleife) und eine zweite Schleife für das Durchlaufen aller Spalten (innere Schleife).
Die Laufvariable k
der äußeren Schleife wird also in der ersten Klammer benutzt, die Laufvariable i
der inneren Schleife in der zweiten Klammer.
for (int k = 0; k < b.length; k++) { for (int i = 0; i < b[k].length; i++) { print(b[k][i] + " "); } println(); }
4 0 0 0 0 0 0 0 0 2
Kurzschreibweise für das Initialisieren
Ähnlich wie bei "normalen" Arrays gibt es eine Kurzschreibweise, um einen neuen Array mit Anfangswerten zu erzeugen. Hier ist die Vorstellung hilfreich, dass es sich um zwei verschachtelte Arrays handelt.
Wir erzeugen als Beispiel den gleichen Array wie oben:
int[][] a = { {4, 0, 0, 0, 0}, {0, 0, 0, 0, 2} };
Es kann übersichtlicher sein, mit Zeilenumbrüchen zu arbeiten:
int[][] a = { {4, 0, 0, 0, 0}, {0, 0, 0, 0, 2} };
Beachten Sie auch, dass Sie beliebige Datentypen wählen können. Hier zwei Beispiele:
String[][] ticTacToe = { {"X", "O", "O"}, {"-", "X", "-"}, {"X", "O", "-"} };
boolean[][] selection = { {false, true}, {false, true}, {true, false}, {false, false} };
Noch mehr Dimensionen?
Unsere herkömmlichen Arrays sind 1-dimensionale Arrays. Im letzten Abschnitt haben wir 2-dimensionale Arrays gesehen. Gibt es auch 3- oder 4-dimensionale Arrays? Ja, natürlich! Man nennt solche Gebilde allgemein Tensoren.
Was wäre ein Beispiel? Wenn Sie die Pixel in einem Bild als 2-dimensionalen Array auffassen, dann wollen Sie für jeden Pixel drei Farbwerte definieren (RGB). Bei einem Bild mit der Auflösung 800x600 bedeutet das: Sie benötigen drei 2-dimensionale Arrays. Als Beispiel schauen wir uns das mit einem Bild der Auflösung 2x2 an:
int[][][] tensor = { { {255, 0}, {0, 0} }, { {0, 255}, {255, 0} }, { {0, 0 }, {0, 255} } };
Als Übung können Sie mal überlegen, wie man die bestimmte Werte anspricht, z.B. alle 255er-Werte, d.h. welche Indexzahlen müssen Sie da verwenden?
Fingerübungen
a) Array ausgeben
Erstellen Sie einen Integer-Array a
mit Dimensionen 5x5.
Verwenden Sie zwei verschachtelte Schleifen, um folgende Ausgabe zu produzieren:
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
int[][] a = new int[5][5]; for (int i = 0; i < a.length; i++) { for (int j = 0; j < a[i].length; j++) { print(a[i][j] + " "); } println(); }
b) Array initialisieren
Erstellen Sie einen Integer-Array a
mit Dimensionen 5x5 und setzen Sie jedes Element auf den Wert 9.
int[][] a = new int[5][5]; for (int i = 0; i < a.length; i++) { for (int j = 0; j < a[i].length; j++) { a[i][j] = 9; } }
Übungsaufgaben
6.6 a) Array auseinander nehmen Level 21 = easy
2 = relativ leicht
3 = mittel
4 = schwierig
5 = hart
Gegeben sei folgender Array:
int[][] a = { {4, 0, 2}, {3, 2, 3}, {1, 2, 3} };
Erzeugen Sie drei einfache Arrays b, c und d, welche jeweils eine Zeile von a enthalten. Array b enthält also { 4, 0, 2 }. Sie sollen das natürlich so programmieren, dass die Inhalte aus a genommen werden.
Testen Sie Ihr Programm mit:
println(b); println(); println(c); println(); println(d);
Sie sollten sehen:
[0] 4 [1] 0 [2] 2 [0] 3 [1] 2 [2] 3 [0] 1 [1] 2 [2] 3
6.6 b) Array befüllen Level 31 = easy
2 = relativ leicht
3 = mittel
4 = schwierig
5 = hart
Gegeben sei ein leeres Array:
int[][] a = new int[3][5];
Schreiben Sie zunächst den Array mit Hilfe von Schleifen auf die Konsole:
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
Versuchen Sie als nächstes, den Array wie folgt zu befüllen. Versuchen Sie, das möglichst ökonomisch zu tun.
1 0 0 0 0 0 1 0 0 0 0 0 1 0 0
Versuchen Sie als nächstes, den Array wie folgt zu befüllen:
0 1 2 3 4 0 1 2 3 4 0 1 2 3 4
Anschließend probieren Sie folgende Befüllung:
0 0 0 0 0 1 1 1 1 1 2 2 2 2 2
Zu guter letzt probieren Sie das hier:
0 1 2 3 4 1 2 3 4 5 2 3 4 5 6
6.6 c) Summe eines zweidimensionalen Array Level 21 = easy
2 = relativ leicht
3 = mittel
4 = schwierig
5 = hart
Gegeben sei folgendes Array:
int[][] a = { {4, 0, 2, 44}, {3, 20, 33, -4}, {12, -30, 6, 110} };
Berechnen Sie die Summe aller Elemente. Im Beispiel sollte das 200 ergeben.
6.6 d) Artikel-Tabelle Level 31 = easy
2 = relativ leicht
3 = mittel
4 = schwierig
5 = hart
Sie schreiben für einen kleinen Laden ein Verwaltungsprogramm. Die Artikel in dem Laden stehen in folgender Tabelle:
int[][] tabelle = { {1001, 5, 500, 0}, {2001, 23, 1200, 0}, {3001, 2, 85, 0} };
In der ersten Spalte steht die Artikelnummer, in der zweiten Spalte die Anzahl der verfügbaren Artikel und in der dritten Spalte der Stückpreis. In der vierten Spalte soll der Gesamtpreis stehen (tut er aber derzeit nicht).
Sie haben zwei Aufgaben:
1. Erzeugen Sie folgenden Ausgabe:
5x Artikel Nr. 1001 à 500 EUR = 0 23x Artikel Nr. 2001 à 1200 EUR = 0 2x Artikel Nr. 3001 à 85 EUR = 0
2. Berechnen Sie dann für jeden Artikel den Gesamtwert aller Arikel dieses Typs und schreiben Sie ihn in die Tabelle zurück (vierte Spalte). Bei Ausgabe sollten Sie sehen:
5x Artikel Nr. 1001 à 500 EUR = 2500 23x Artikel Nr. 2001 à 1200 EUR = 27600 2x Artikel Nr. 3001 à 85 EUR = 170
6.6 e) Multiplikation Matrix-Vektor Level 41 = easy
2 = relativ leicht
3 = mittel
4 = schwierig
5 = hart
Um diese Aufgabe zu lösen, müssen Sie wissen, wie Matrizenmultiplikation funktioniert. Wenn Sie das Thema nicht in der Schule hatten, können Sie es entweder unter dem gegebenen Link nachlesen (oder auf YouTube nachsehen) oder Sie lassen diese Aufgabe einfach aus.
Gegeben sei die folgende 2x3-Matrix m
int[][] m = { {1, 1, 2}, {2, 0, 1} };
und folgender Vektor v
int[] v = { 10, 20, 30 };
Berechnen Sie das Ergebnis der Multiplikation von m
mit v
und schreiben Sie das Ergebnis in den neuen Vektor w
der Länge 2:
int[] w = new int[2];
Sie sollten bei Ausgabe von w
erhalten:
[0] 90 [1] 50
Testen Sie Ihren Code auch mit anderen Werten und anderen Dimensionen für Matrix m
und Vektor v
.