Über Listen - Theorie Lektion 5

Erstellt von Frithjof Thu, 02 Aug 2007 20:01:00 GMT

Diese Lektion und vielleicht noch eine weitere, dann fängst du aber wirklich an, ein Spiel in Ruby zu programmieren. Jetzt lernst du ein sehr wichtiges Dings. Das Dings gehört zu den sogenannten Datenstrukturen.

Du weißt bereits, wie man eine Zahl oder eine Zeichenkette in Ruby verwendet. Was aber, wenn du gleich mehrere Zahlen oder Zeichenketten als ein Ganzes verwenden möchtest, sozusagen eine Liste mit Zahlen oder Zeichenketten?

Einfache Liste in Ruby

Schau dir diesen Code an:


# theorie_05.rb

zahlen_liste = [2, 4, 6, 8, 10]

planeten_liste = [
  "Merkur",  "Venus", 
  "Erde",    "Mars", 
  "Jupiter", "Saturn", 
  "Uranus", "Neptun",
]

irgendwas_liste = ["Mars", 95, "95", 95, "Quark"]

leere_liste = []

Du siehst, eine Liste ist ganz einfach zu erstellen. Der Anfang einer Liste wird mit der öffnenden eckigen Klammer [ markiert, das Ende der Liste mit der schließenden eckigen Klammer ]. Zwischen die Klammern schreibst die Glieder der Liste und trennst sie jeweils mit einem Komma ab. Ein Komma darf auch nach dem letzten Glied in einer Liste stehen, aber nicht vor dem ersten. Man bezeichnet die Dinge in einer Liste als Mitglieder oder Elemente der Liste. Eine Liste ohne Elemente heißt die leere Liste.

Eine Liste kann aus einheitlichen Elementen bestehen, also bspw. nur Zahlen. Sie kann aber auch Elemente verschiedenen Typs enthalten, also bspw. Zeichenketten und Zahlen. Ein Element einer Liste kann sogar selbst wieder eine Liste sein!

Eine Liste kann mehrere identische Elemente enthalten. Bspw. in der irgendwas_liste ist die 95 zweimal enthalten. Oder dreimal? Nein, für Ruby ist das Element 95 eine Zahl, das Element "95" aber eine Zeichenkette. Daher ist die Zahl 95 nur zweimal enthalten.

Verteile die Elemente einer Liste über mehrere Zeilen, damit es besser lesbar ist, was in der Liste so alles enthalten ist. Du brauchst die Liste also nicht in eine einzige Zeile zu quetschen.

Listen nennt man auch Array (engl. für Anordung, Reihe) oder Vektor. Genaugenommen ist eine Liste etwas mehr als ein Array. Bei einer Liste kennt jedes Element ihre unmittelbaren Nachbarelemente, entweder das davor und das danach oder nur eines von beiden. Das was wir hier in diesem Artikel als Liste kennen lernen ist daher genaugenommen nur ein Array, weil die Elemente sich selbst untereinander nicht kennen. Wir bleiben aber hier trotzdem bei dem Begriff Liste, weil man eher begreift, was gemeint ist.

Ausgabe einer einfachen Liste

Angenommen wir definieren eine Einkaufsliste mit den Elementen Butter, Milch, Honig und Brot. Dann können wir die Liste natürlich einfach mit dem puts Befehl ausgeben. Dabei wird jedes Element der Liste in einer neuen Zeile ausgegeben.

Ruby bietet dir aber noch eine schönere Ausgabe der Liste an. Auf englisch heißt das pretty print (schöner Druck). Verwende statt puts den Befehl pp (dabei steht pp für pretty print). Bevor du diesen Befehl in deinem Programm verwenden kannst, muss du ihn im Programm bekannt machen über ein require ‘pp’ am Anfang der Datei:


require 'pp'

# Einzelne Einkaufslisten
tegut = ["Butter", "Milch", "Honig", "Brot"]
obi   = ["Schrauben", "Leimholz", "Kabel", "Lampe"]
dm    = ["Duschbad für Mama",    "Deo für Papa", 
         "Haarspange für Livia", "Zahnbürste für Peter"]

# Gesamte Einkaufsliste, enthält die einzelnen Listen
einkauf = [tegut, obi, dm]

# Normale Ausgabe
puts einkauf

# Schickere Ausgabe mit pretty print
pp einkauf

# Ausgabe des dritten Elementes der Liste
pp einkauf[2]

Du siehst hier auch, dass eine Liste als Elemente wiederum Listen enthalten kann. Die Liste obi mit ihren Elementen "Schrauben", "Leimholz", "Kabel", "Lampe" wird in der Liste einkauf als zweites Element gespeichert.

Die gesamte Liste auszugeben ist gut und schön. Häufiger jedoch möchtest du nur bestimmte Elemente der Liste ausgeben. Ruby nummeriert die Elemente durch, sodass du einfach nur die Nummer des Elementes angeben musst. Das machst du, indem du direkt an den Variablennamen der Liste die gewünschte Nummer in eckige Klammern anhängst.

Aber Achtung: Ruby beginnt beim Durchnummerieren der Elemente in einer Liste immer mit 0, nicht mit 1! Möchtest du das dritte Element in der Einkaufsliste einkauf ausgeben, musst du somit einkauf[2] schreiben, nicht einkauf[3], weil das erste Element in der Liste nämlich nicht einkauf[1], sondern einkauf[0] ist.

Hash – Liste mit Index

Ruby kennt noch eine weitere wichtige listenähnliche Datenstruktur. Es ist eigentlich eine Art Doppelliste bestehend aus zwei Listen: eine Liste mit Namen und eine Liste, die für jeden Namen den zugehörigen Wert enthält. Den Namen nennt man auch Schlüssel oder englisch Key oder Index. Ein bestimmter Key darf in dieser Liste nur höchstens einmal vorkommen. Daher heißt diese Datenstruktur auch Indextabelle oder englisch Hashtable oder einfach nur ein Hash. Verwende einen Hash immer dann, wenn du schnell über einen Schlüsselnamen auf einen zugehörigen Wert zugreifen möchtest.

Der folgende Hash legt für jeden Namen eines deutschen Zahlwortes oder einer natürlichen Zahl von 1 bis 10 als zugehörigen Wert das Zahlwort in spanischer Sprache ab.


require 'pp'

deutsch_spanisch = {
  1        => "uno",
  "eins"   => "uno",
  2        => "dos",
  "zwei"   => "dos",
  3        => "tres",
  "drei"   => "tres",
  4        => "cuatro",
  "vier"   => "cuatro",
  5        => "cinco", 
  "fuenf"  => "cinco", 
  6        => "seis",
  "sechs"  => "seis",
  7        => "siete",
  "sieben" => "siete",
  8        => "ocho",
  "acht"   => "ocho",
  9        => "nueve",
  "neun"   => "nueve",
  10       => "diez",
  "zehn"   => "diez",
}
pp deutsch_spanisch
puts "Vier heisst auf Spanisch #{deutsch_spanisch['vier']}." 
puts "Acht heisst auf Spanisch #{deutsch_spanisch[8]}." 

Ein Hash wird ähnlich einer Liste definiert aber mit folgenden Unterschieden. Der Anfang und das Ende des Hash werden mit geschweiften Klammern (anstatt eckiger) markiert. Die Elemente des Hash werden zwar auch mit Komma getrennt, aber ein Element besteht immer aus einem Name-Wert-Paar. Zuerst schreibst du den Namen hin (eine Zahl oder eine Zeichenkette, oder …), dann einen nach rechts gerichteten Pfeil => und auf die rechte Seite des Pfeils schreibst du den Wert. Lies den Pfeil als wenn du sprichst: dem Namen (oder Key) sowieso ordne ich den Wert soundso zu.

Du siehst in unserem deutsch_spanisch Hash auch, dass es zwar gleiche Werte auf der rechten Seite geben kann, auf der linken Seite darf jeder Key aber nur höchstens einmal vorkommen. Kommt ein Key aber trotzdem auf der linken Seite mehrmals vor, dann speichert Ruby nur den zuletzt genannten Wert im Hash ab.


require 'pp'

deutsch_spanisch = {
  "acht" => "ocho",
  "acht" => "otscho",
}
puts "Acht heisst auf Spanisch #{deutsch_spanisch['acht']}." 

Dieser Hash hat nur ein Element! Der Wert für den Key acht wird beim zweiten mal überschrieben und hat am Ende nur einen Wert otscho.

Durchgehen von Listen und Hashes

Nicht selten muss man eine Liste durchgehen und mit jedem Element der Liste etwas bestimmtes unternehmen. Oder man möchte für alle Keys in einem Hash die Werte untersuchen. Schauen wir uns zunächst an, wie man für eine Liste alle Elemente durchgeht:



# Schleife über eine Liste

planeten = [
  "Merkur",  "Venus", 
  "Erde",    "Mars", 
  "Jupiter", "Saturn", 
  "Uranus", "Neptun",
]

for planet in planeten
  # Nur die Planeten ausgeben, in deren Namen ein e vorkommt.
  if planet.include?("e")
    puts planet
  end
end

Das Durchgehen einer Liste nennt man auch einen Loop über eine Liste machen. Loop (englisch für Schleife) deswegen, weil man schleifenartig ein Element nach dem anderen abklappert. Die Schleife beginnt mit dem for planet in planeten und endet mit end. Am Beginn der Schleife wird der Variablen planet bei jedem Durchgang der Wert des jeweils nächsten Elements zugewiesen. Diese Variable ist nur innerhalb der Schleife bekannt. Man nennt sie daher auch Schleifenvariable. Wenn alle Elemente in der Schleife behandelt wurden, setzt Ruby das Programm nach dem end fort.

Für einen Hash könnte ein Schleifendurchgang etwa so aussehen.



# Schleife über einen Hash

de_esp = {
  "eins"   => "uno",
  "zwei"   => "dos",
  "drei"   => "tres",
  "vier"   => "cuatro",
  "fuenf"  => "cinco", 
  "sechs"  => "seis",
  "sieben" => "siete",
  "acht"   => "ocho",
  "neun"   => "nueve",
  "zehn"   => "diez",
}

for key in de_esp.keys
  if de_esp[key].include?("t")
    puts de_esp[key]
  end
end

Die Liste aller Keys für den Hash de_esp bekommen wir mit de_esp.keys. Diese Liste gehen wir durch und verwenden den jeweiligen Key dazu, uns den zugehörigen Wert aus dem Hash zu holen—hier das Zahlwort auf Spanisch. Enthält der Hashwert (das spanische Zahlwort) ein t im Namen, dann geben wir es mit puts aus.

Natürlich hat Ruby noch mehrer Möglichkeiten, Schleifen über Listen und Hashes zu machen. Aber die hier vorgestellte for-Schleife ist gut lesbar und fürs erste ausreichend.

Üben mit Peter und Livia

Livia: Schreibe die Einkaufsliste von oben als Hash um. Verwende dabei die Variablennamen der einzelnen Einkaufslisten (tegut, obi, dm) als Keys im Hash! Was fällt dir bei der pretty print Ausgabe bezüglich der Reihenfolgen von Liste und Hash auf?

Peter: Zähle bitte auf, wozu man alles die eckigen Klammern [ ] bei Listen und Hashes benutzt!

Lektion 8 - Projekt Euler Problem 1 3

Erstellt von Frithjof Fri, 20 Apr 2007 20:21:00 GMT

In den folgenden drei Lektionen wollen wir kein konkretes Thema verfolgen, sondern die Dinge, die wir gelernt haben etwas festigen. Das soll aber nicht heißen, dass wir die Zeit verstreichen lassen, ohne etwas Neues zu lernen! Im Gegenteil.

Wie können wir unsere bisher erworbenen Kenntnisse besser anwenden und überprüfen, als wenn wir an einem Wettbewerb teilnehmen? Was meinst du? Hast du Lust, dich mit anderen zu messen? Okay, los geht’s!

Auf der Website Projekt Euler findest du eine Sammlung von Problemen unterschiedlicher Schwierigkeitsgrade. Wir suchen uns dort einfach mal das erste Problem aus und versuchen es mit Ruby zu lösen. Auch eine gute Gelegenheit, sich etwas über den Mathematiker Leonhard Euler zu belesen.

Das erste Problem von Projekt Euler lautet:

Problem 1

Wenn wir alle natürlichen Zahlen kleiner als 10 auflisten, die durch 3 oder 5 teilbar sind, erhalten wir die Zahlenfolge 3, 5, 6 und 9. Die Summe dieser Zahlenfolge ist 23.

Finde die Summe aller Vielfache von 3 und 5 kleiner als 1000.

Wenn du möchtest kannst du zunächst auf einem Schmierblatt selbst versuchen, wie sich das Problem mit Ruby lösen lässt. Ich schau mal kurz weg … hast du’s? Wir können es auch zusammen machen.

Beim Versuch, das Problem mit Blatt und Bleistift lösen zu wollen, merkst du sicher schnell, dass das ziemlich langweilig ist (immer, wenn man dieses Gefühl der Langeweile in der Mathematik bekommt, bietet sich der Einsatz eines Computers an, denn der kennt keine Langeweile).

Wir würden jede Zahl von 1 bis 999 (die 1000 sollen wir ja nicht mit berücksichtigen) zunächst testen, ob sie durch 3 oder durch 5 teilbar ist. Wenn ja, dann nehmen wir diese Zahl und addieren sie zu unserer Summe hinzu. Das würde dann etwa so aussehen:

Zahl Teilbar durch 3? Teilbar durch 5? Summe
1 nein nein 0
2 nein nein 0
3 ja nein 0 + 3 = 3
4 nein nein 3
5 nein ja 3 + 5 = 8
6 ja nein 8 + 6 = 14
7 nein nein 14
8 nein nein 14
9 ja nein 14 + 9 = 23
10 nein ja 23 + 10 = 33
11 nein nein 33
12 ja nein 33 + 12 = 45
13 nein nein 45
14 nein nein 45
15 ja ja 45 + 15 = 60
... ...

Wir zerlegen das Problem in folgende Teilprobleme:

  1. Testen auf Teilbarkeit durch 3
  2. Testen auf Teilbarkeit durch 5
  3. Aufaddieren von Zahlen
  4. Durchlaufen aller Zahlen von 1 bis 999 in einer Schleife

Testen auf Teilbarkeit durch 3

Wie testen wir mit Ruby, ob eine Zahl durch 3 teilbar ist? Wann ist eine Zahl durch 3 teilbar?

Eine Zahl zahl ist durch 3 teilbar, wenn bei der ganzzahligen Division von zahl durch 3 der Rest 0 entsteht. Die 2 geht zum Beispiel 0 mal durch 3 zu teilen und es entsteht ein Rest von 2. Bei der 7 hingegen kommt bei der Division durch 3 das Ergebnis 2 Rest 1 heraus. Bei der 3 oder der 6 oder der 9 aber geht die Division mit dem Rest 0 auf.

Mit Ruby können wir leicht testen, ob eine Zahl bei Division durch 3 den Rest 0 hinterlässt, indem wir an die Zahl die Nachricht rest_bei_div mit der Zusatzinformation 3 schicken. Probieren wir es mal für die 7 und die 6:


# lektion_08.rb

require 'rubykids'

zahl = 7

if zahl.rest_bei_div(3) == 0
  schreibe "#{zahl} ist durch 3 teilbar!" 
else
  schreibe "#{zahl} ist nicht durch 3 teilbar!" 
end

zahl = 6

if zahl.rest_bei_div(3) == 0
  schreibe "#{zahl} ist durch 3 teilbar!" 
else
  schreibe "#{zahl} ist nicht durch 3 teilbar!" 
end

Testen auf Teilbarkeit durch 5

Das Testen der Teilbarkeit durch 5 geht genauso. Wir brauchen nur die Zusatzinformation, die wir mit der Nachricht rest_bei_div an die zahl schicken, abzuändern.


...
if zahl.rest_bei_div(5) == 0
...

Aufaddieren von Zahlen

Angenommen wir haben die Variable summe, so können wir beispielsweise die 3 hinzuaddieren, indem wir einfach summe + 3 schreiben und diesen neuen Wert wieder der Variablen summe mit dem Gleichheitszeichen zuweisen.


# lektion_08.rb

require 'rubykids'

summe = 0

summe = summe + 3
summe = summe + 5
summe = summe + 6
summe = summe + 9

# ... und immer so weiter

schreibe "Summe ist: #{summe}" 

Ruby legt viel Wert auf die Möglichkeit sehr kompakten Code zu schreiben. Beim Summieren sparen wir uns daher das Wiederholen der Variablen auf der rechten Seite vom Gleichheitszeichen. Das Plus-Zeichen würde dann aber in der Luft hängen, daher schreibt man es vor das Gleichheitszeichen. Das sieht dann so aus:


# lektion_08.rb

require 'rubykids'

summe = 0

summe += 3
summe += 5
summe += 6
summe += 9

# ... und immer so weiter

schreibe "Summe ist: #{summe}" 

Im Matheunterricht darfst du soetwas aber natürlich nicht schreiben! ;-)

Durchlaufen aller Zahlen von 1 bis 1000 in einer Schleife

Schleifen haben wir auch schon kennen gelernt. Folgender Code sollte dir keine Schwierigkeiten bereiten:


# lektion_08.rb

require 'rubykids'

zahl = 0

1000.mal do
  zahl = zahl + 1
  schreib "\r zahl=#{zahl}" 
  schlafe_kurz
end

Wie du siehst, verwenden wir hier wieder den Trick mit dem Wagenrücklauf (carriage return), den wir bereits in Lektion 7 kennen gelernt haben, um immer auf derselben Zeile die Zahlen auszugeben. Außerdem ist hier der Befehl schlafe_kurz neu. Der zwingt Ruby dazu, kurz zu warten. Würden wir diesen Befehl weglassen (probiere es!), dann würden wir nicht sehen, wie Ruby von 1 bis 1000 hochzählt, weil Ruby das so unheimlich schnell tut, dass wir sofort die 1000 sehen würden. Das schlafe_kurz lassen wir nachher, wenn wir unser fertiges Programm zur Lösung des Problems zusammenbauen natürlich weg.

Lösung für Problem 1 projecteuler.net mit Ruby

Okay, nun haben wir alles, was wir für die Lösung des Problems brauchen. Hier ist sie:


# lektion_08.rb

require 'rubykids'

maximum = 1000
summe = zahl = 0

maximum.mal do
  zahl = zahl + 1
  summe += zahl if (zahl.rest_bei_div(3) == 0 or zahl.rest_bei_div(5) == 0 and zahl < maximum)
end
schreibe "Die Summe aller Vielfache von 3 und 5 kleiner #{maximum} ist #{summe}." 

In der Zeile

  ...
  summe += zahl if (zahl.rest_bei_div(3) == 0 or zahl.rest_bei_div(5) == 0 and zahl < maximum)
  ...

passiert ziemlich viel auf einmal. In einer einzigen Zeile testen wir hier, ob die aktuelle Zahl, die wir in der Schleife gerade bearbeiten durch 3 oder durch 5 teilbar ist und ob sie noch kleiner als 1000 ist. Gleichzeitig addieren wir die zahl auch zur Summe hinzu, wenn die Bedingungen erfüllt sind.

Wir reihen hier die Tests auf Teilbarkeit durch 3 und 5 aneinander. Da nur eine von beiden Bedingungen erfüllt sein muss, verbinden wir beide Bedingungen mit dem Operator or, das ist englisch und bedeutet zu deutsch oder. Egal, ob die zahl nun durch 3 oder 5 teilbar ist, sie muss auf jeden Fall kleiner als 1000 sein. Daher verbinden wir den Test darauf nicht mit or, sondern mit and, was wieder englisch ist und zu deutsch und bedeutet.

Boolesche Algebra

Diese Bedingungen, die wahr oder falsch sein können, nennt man auch Boolesche Ausdrücke. Und das Verbinden dieser Ausdrücke mit Operatoren or und and nennt man Boolesche Algebra.

Wenn wir dafür, dass eine Bedingung wahr ist eine 1 schreiben würden und dafür, dass eine Bedingung falsch ist eine 0, dann kannst du dir das or wie ein Plus + und das and wie ein Mal * in der normalen Mathematik vorstellen. Dann gilt in der boolschen Algebra folgendes:

falschorfalsch= falsch d.h. 0 + 0 = 0
falschorwahr= wahr d.h. 0 + 1 = 1
wahrorfalsch= wahr d.h. 1 + 0 = 1
wahrorwahr= wahr d.h. 1 + 1 = 1
falschandfalsch= falsch d.h. 0 * 0 = 0
falschandwahr= falsch d.h. 0 * 1 = 0
wahrandfalsch= falsch d.h. 1 * 0 = 0
wahrandwahr= wahr d.h. 1 * 1 = 1

Du siehst, eine aus zwei mit or verknüpften Bedingungen bestehende Bedingung ist immer dann wahr, wenn eine von beiden Bedingungen (egal welche) wahr ist. Aber, eine aus zwei mit and verknüpften Bedingungen bestehende Bedingung ist nur dann wahr, wenn beide Bedingungen zugleich wahr sind.

Mehr zu Boolescher Algebra findest du bei Wikipedia.

Peter und Livia

Peter: Wieso durchlaufen wir denn alle Zahlen von 1 bis 1000? Wir könnten doch zumindest die 1 und 2 schon mal auslassen und gleich bei der 3 starten, oder?

Livia: Ja das stimmt.

Peter: Ich habe die Variable maximum statt auf 1000 auf 1000000 (eine Million) gesetzt und das Programm dauert ganz schön lange. Warum?

Livia: Je größer die maximale Zahl, um so mehr Vergleiche müssen doch gemacht werden. Und das dauert Zeit. Wir konnten ja das Problem nur mit den Mitteln lösen, die wir bisher von Ruby kennen gelernt haben. Das Programm lässt sich aber auf jeden Fall noch verbessern, so dass es mindestens doppelt so schnell läuft. Dazu musst du aber noch erst etwas mehr von Ruby lernen. Ich kann’s schon (sie lächelt verschmitzt)! Oder du versuchst, mit mehr Mathematik die Laufzeit des Programms zu verringern. Du siehst: damit dein Programm weniger Zeit für die Ausführung benötigt, musst du mehr Zeit in seine Entwicklung investieren. Das ist so ähnlich wie bei der Goldenen Regel der Mechanik Was man an Kraft spart, muss man an Weg zulegen, nur dass man hier sagen müsste:

Was sich der Entwickler an Zeit spart, muss der Anwender an Zeit mitbringen.
Peter: Die Zeile

...
summe = zahl = 0
...
verstehe ich nicht. Was soll das mit den zwei Gleichheitszeichen nacheinander bedeuten?

Livia: Du must das von rechts nach links lesen: Die Null wird der Variablen zahl zugewiesen (du erinnerst dich an die Schublade). Das Ergebnis dieser Zuweisung ist nun der Inhalt der Schublade, eh Variable zahl, der wiederum der Variablen summe zugewiesen wird. Nach dieser Doppelzuweisung haben beide Variablen (zahl und summe) denselben Wert, nämlich 0.

- Änderungen
17.07.2007, Im Abschnitt Boolesche Algebra die Übersicht beim and korrigiert.
22.09.2007, Unicodeproblem mit Umlauten

Lektion 3 - Wir malen zwei Häuser... 2

Erstellt von Frithjof Sat, 24 Mar 2007 18:11:00 GMT

In Lektion 2 haben wir ein Haus gemalt (d.h. in der DOS-Box ausgegeben). Nun wollen wir mehr als ein Haus ausgeben. Wir wollen eine ganze Reihe mit Häusern ausgeben! Fangen wir aber erst einmal mit 2 Häusern an. Für die DOS-Box Ausgabe haben wir zwei Möglichkeiten: entweder wir geben beide Häuser untereinander, oder nebeneinander aus. Der erste Fall ist einfacher, also fangen wir damit an:


  01 # lektion_03.rb
  02 
  03 require 'rubykids'
  04 
  05 schreibe_leer(2)
  06 schreibe " /^\\ " 
  07 schreibe " |.|  " 
  08 schreibe " |_|  " 
  09 schreibe_leer
  10 
  11 schreibe_leer(2)
  12 schreibe " /^\\ " 
  13 schreibe " |.|  " 
  14 schreibe " |_|  " 
  15 schreibe_leer

Programm ausführen:


C:\entwicklung>ruby lektion_03.rb

Prima es geht!

Wie findest du diese Lösung? Ich finde sie nicht so schön. Stört dich nicht auch, dass du im Programm alles doppelt hingeschrieben hast? Wie soll das Programm aussehen, wenn wir 3 oder 5 oder 500 Häuser ausgeben wollen? Da würde sich ja bald niemand mehr im Programm zurechtfinden (auch Mama nicht)! Wir brauchen eine Möglichkeit, mit der wir die schreibe-Befehle für das Haus nur einmal angeben, Ruby aber dazu bringen, diese Befehle mehrmals auszuführen.

Wiederholungen in Ruby – auch genannt Schleifen

Aus dem Musikunterricht kennst du sicher das Zeichen, das der Komponist verwendet, wenn er möchte, dass der Interpret seines Stückes (derjenige der es singen oder spielen darf) einen Notenabschnitt wiederhollen soll. Ist man beim Wiederholungszeichen :| angelangt, geht man zum unmittelbar vorherigen |: zurück und spielt oder singt den Abschnitt nochmals.

So etwas ähnliches gibt es auch in Ruby:


# lektion_03.rb

require 'rubykids'

2.mal do
  schreibe_leer(2)
  schreibe " /^\\ " 
  schreibe " |.|  " 
  schreibe " |_|  " 
  schreibe_leer
end

Probiere es aus! Das Haus wird nun zweimal ausgegeben – wie zuvor – allerdings mussten wir die schreibe-Befehle und die Zeichenketten für das Haus nur einmal im Rubyprogramm angeben. 6 Zeilen konnten wir wegstreichen und mussten 2 dazu nehmen, insgesamt also ist das Programm um 4 Zeilen kürzer geworden.

Ändere die 2 in eine 4 oder irgendeine beliebige Zahl! Bevor du das nächste mal in Urlaub fährst, kannst du vielleicht die Zahl 30000000 verwenden und nachschauen, ob das Programm nach deinem Urlaub fertig ist!

Ruby kennt aber noch mehrere Möglichkeiten, eine Wiederholung auszudrücken. Wir werden bestimmt noch einige davon in den nächsten Lektionen kennenlernen. Einen Codeabschnitt, der auf diese Art mehrmals durchlaufen wird nennt man auch eine Schleife (englisch loop).

Was ist neu?

Schauen wir uns das 2.mal do … end etwas genauer an. Zuerst schreiben wir eine Zahl hin (die 2), dann einen Punkt und dann den Befehl mal. Was soll das bedeuten? Ruby kennt außer Zeichenketten auch Zahlen. So wie eine Zeichenkette in Ruby String heißt, heißt eine ganze Zahl in Ruby Fixnum oder Integer. Der Punkt nach der Zahl bedeutet, dass wir der Zahl eine Nachricht schicken möchten und zwar soll die Nachricht mal heißen. 2.mal bedeutet also wir schicken an die Zahl 2 die Nachricht mal. Allgemein gesprochen möchten wir, dass die Zahl, an die wir die Nachricht mal schicken, etwas sooft wiederholt, wie sie groß ist. 100.mal do…end bedeutet dann, dass wir 100 mal etwas wiederholen möchten.

Das, was wir wiederholen möchten, fassen wir in einem Codeblock zwischen den Worten do und end zusammen. Ein do leitet immer einen Codeblock ein und ein end schließt ihn wieder ab. Dieser Codeblock ist somit eine Zusatzinformation, die wir zusammen mit der Nachricht mal an die Zahl 2 schicken.

Bei der Nachricht mal entspricht das do somit dem |:, und das end dem :| in der Musik.

Einen kurzen Codeblock können wir auch in eine einzige Zeile schreiben. Um dabei noch mehr Platz zu sparen bietet Ruby die Möglichkeit, das do und end jeweils durch eine öffnende bzw. schließende geschweifte Klammer zu ersetzen. Das ist für unsere deutschen Tastaturen zugegeben nicht gerade eine Erleichterung, aber naja, der Code wird trotzdem etwas übersichtlicher.


# Einzeilige Wiederholung mit geschweiften Klammern

require 'rubykids'

3.mal { schreibe " Hurra, ich kann Ruby!" }

Peter und Livia

Peter: Ich verstehe nicht, warum ich an die Zahl 2 eine Nachricht schicken kann?

Livia: Bei Ruby ist die Zahl 2 nicht nur eine natürliche Zahl, sondern sie ist ein bestimmtes Objekt aus der Klasse Fixnum. Jede Klasse kann bestimmen, auf welche Nachrichten ihre Objekte reagieren und für welche sie taub sind. Landet eine falsche Nachricht im Briefkasten eines Objektes der Klasse, beschwert es sich bei Ruby und Ruby bricht mit einem Fehler ab. Andernfalls schaut sich das Objekt noch an, ob es zur Nachricht eine Zusatzinformation gibt und macht dann etwas damit.

- Änderungen
22.09.2007, Unicodeproblem mit Umlauten