Behandelte Konzepte/Konstrukte: Array, Index, length, zwei-dimensionales Array

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.

Neueste Aktualisierungen (zuletzt 23.01.2024)
  • 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.

Lösung
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.

Lösung
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);
Erklärung
Normalerweise kann man einen Array nicht einfach ausdrucken, da hier ja mehrere Werte vorliegen. Man müsste also eigentlich mit einer Schleife die Einzelwerte abrufen und mit 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 oder String[] 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 mit foo.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.

Lösung
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.

Lösung
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
Tipp
Verwenden Sie 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!

Tipp
Besetzen Sie die ersten zwei Elemente im Array direkt mit je 1 und starten Sie in der Schleife ab dem dritten Element (Index 2).

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
Tipp
Verwenden Sie eine neue int-Variable, um die Summe schrittweise "einzusammeln".

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 };
Tipp
Sie benötigen ein 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!

Tipp

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.

Tipp
Sie laufen mit einer For-Schleife und Laufvariablen 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
Tipp
Wenn Sie Schwierigkeiten haben (z.B. weil Ihr Array hinterher 10 an allen Stellen enthält), dann probieren Sie zunächst die Aufgabe, alle Element nach links zu schieben.

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
Tipp
Verwenden Sie random(100). Sie erhalten einen zufälligen Wert zwischen 0 und 100. Wie können Sie diesen Wert nutzen, um nur in 5% aller Fälle eine Variable auf 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.

Tipp
Verwenden Sie eine boolesche Variable. Welchen Wert hat diese zu Beginn, was passiert damit in der Schleife? Am Ende der Schleife soll die Variable nur dann 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
Jetzt wollen wir noch das Geschlecht repräsentieren. Wir nutzen einen Array von booleans, wobei true weiblich bedeutet:

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.

Tipp
Jeder Buchstabe und jedes Zeichen hat einen eindeutigen "Zeichencode", eine ganze Zahl. In der Systemvariablen 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.

Tipp

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.

Lösung
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.

Lösung
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)

Tipp
Wenn Sie die Bilder schematisch benennen, z.B. bild1.jpg, bild2.jpg, bild3.jpg usw. können Sie das Anlegen der PImage-Objekte ökonomisch mit einer Schleife regeln.

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
Lösung
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.

Lösung
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
Tipp
Die Lösung besteht aus drei Zeilen, denn Sie können z.B. der Variable b einfach das erste Element von a zuweisen.

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
Tipp
Sie benötigen nur eine Schleife (und nicht zwei verschachtelte).

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
Tipp
Hier benötigen Sie zwei verschachtelte Schleifen.

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.

Tipp
Verwenden Sie eine verschachtelte Schleife, um alle Elemente zu durchlaufen. Außerhalb der Schleife benötigen Sie außerdem eine Variable, um die Summe "einzusammeln" und am Ende auszugeben.

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.