Fast alle Programmiersprachen stellen sogenannte Arrays (zu deutsch: Felder oder Feldvariablen) zur Verfügung. Sie sind nützlich, wenn ganze Folgen von Werten verarbeitet werden sollen.
Angenommen, man möchte mit einem Ruby-Programm einen Tag lang jede Stunde die Temperatur messen, um anschließend die Durchschnittstemperatur zu berechnen. Auskunft über die Temperatur liefert in den folgenden beiden Beispielen die fiktive Funktion aktuelle_temperatur
. (Wenn Sie den Code testen wollen, schreiben Sie einfach aktuelle_temperatur = 10
vorneweg, und ersetzen Sie sleep 3600
durch sleep 1
, sonst dauert die Ausführung des Programms 24 Stunden!) Ohne die Verwendung eines Arrays würde das Programm so aussehen:
temp_0 = aktuelle_temperatur sleep 3600 temp_1 = aktuelle_temperatur sleep 3600 temp_2 = aktuelle_temperatur sleep 3600 temp_3 = aktuelle_temperatur sleep 3600 temp_4 = aktuelle_temperatur sleep 3600 # hier haben wir 24 Zeilen ausgelassen.... temp_22 = aktuelle_temperatur sleep 3600 temp_23 = aktuelle_temperatur summe_temperaturen = temp_0 + temp_1 + temp_2 + temp_3 + temp_4 # + 19 weitere Variablen... durchschnitt = summe_temperaturen / 24 puts "Durchschnittstemperatur: #{durchschnitt}"
Das ist ein ziemlich umständliches Vorgehen! Jedes Messergebnis braucht eine eigene Variable, und eine Umstellung des Programms auf eine Messung alle 10 Minuten oder auf einen größeren Zeitraum (eine Woche, ein Jahr!) würde noch sehr viel mehr Variablen und sehr viel Schreibarbeit erfordern.
Viel einfacher und übersichlicher geht es mit Arrays:
messungen = [] 24.times do messungen << aktuelle_temperatur sleep 3600 end summe_temperaturen = 0 messungen.each do |temperatur| summe_temperaturen += temperatur end durchschnitt = summe_temperaturen / 24 puts "Durchschnittstemperatur: #{durchschnitt}"
In Zeile 1 wird mit messungen = []
ein leeres Array mit dem Variablennamen messungen
angelegt. In Zeile 3-6 wird mittels der Methode times
vierundzwanzig mal eine Messung durchgeführt, das Ergebnis dem Array Messungen mit dem Operator <<
hinzugefügt, anschließend jeweils 3600 Sekunden gewartet. Nach der Ausführung dieses Codeabschnitts (und einem Tag Wartezeit!) enthält das Array messungen
24 Werte.
In Zeile 9 wird die Variable zur Speicherung der Summe aller Temperaturen definiert und auf den Wert 0 gesetzt. In den Zeilen 10-12 wird diese Summe berechnet. messungen.each
sorgt dafür, dass der Code zwischen do
und end
(ein sogenannter Block) für jedes Element von messungen
einmal durchgeführt wird. Das jeweilige Element des Arrays wird mit |temperatur|
an den Block übergeben. (Anmerkung 1: summe_temperaturen += temperatur
ist übrigens eine verkürzte Schreibweise für summe_temperaturen = summe_temperaturen + temperatur
) (Anmerkung 2: Eleganter bildet man in Ruby Summen mit inject
, aber so ist es für Einsteiger erst einmal leichter verständlich)
Zeile 14 berechnet dann schließlich die Durchschnittstemperatur, indem die Summe durch die Anzahl der Messungen geteilt wird. Damit man den Code an dieser Stelle nicht ändern muß, wenn die Anzahl der Messungen sich ändert, wird hier nicht durch 24 geteilt, sondern durch die Anzahl der Werte, die das Array enthält. Diesen Wert ermittelt man mit messungen.size
.
Arrays in Sonic Pi
Ein häufiger Anwendungsfall für Arrays in Sonic Pi ist die Verwendung in Kombination mit choose. Im folgenden Beispiel wird aus dem Array [:bd_haus, :drum_snare_hard, :drum_cymbal_closed]
bei jedem Schleifendurchgang eines der drei Samples zufällig ausgewählt und abgespielt:
live_loop :chooser do sample [:bd_haus, :drum_snare_hard, :drum_cymbal_closed].choose sleep 0.25 end
Ringe
Auch für Abfolgen Notenwerten, Pausen oder Effektparametern lassen sich Arrays verwenden. Sehr viel geeigneter sind aber Ringe. Ringe sind im Prinzip auch Arrays, sie haben aber einen entscheidenden Vorteil: Sie verhalten sich so, als seien sie endlos lang, sie sind (Überraschung!) ringförmig. Im folgenden Beispiel wird eine Tonfolge in einem Array gespeichert. tonfolge[0]
liefert den ersten Wert des Arrays, tonfolge[1]
den zweiten, tonfolge[2]
den dritten. tonfolge[3]
allerdings gibt nil
, d.h. „Nichts“ zurück, dementsprechend spielt play tonfolge[3]
auch keinen Ton.
tonfolge = [:c4, :d4, :e4] play tonfolge[0] sleep 1 play tonfolge[1] sleep 1 play tonfolge[2] sleep 1 play tonfolge[3]
Wenn man die Tonfolge mehrmals (im Prinzip endlos) wiederholen will, verwendet man in Sonic Pi besser einen Ring:
tonfolge = ring :c4, :d4, :e4 play tonfolge[0] sleep 1 play tonfolge[1] sleep 1 play tonfolge[2] sleep 1 play tonfolge[3] sleep 1 play tonfolge[4] # und so weiter
In diesem Fall spielt Sonic Pi mit play tonfolge[3]
wieder den ersten Wert des Rings ab, mit play tonfolge[4]
den zweiten, und so weiter…
Folgender Code spielt die Tonfolge in Endlosschleife:
tonfolge = ring :c4, :d4, :e4 live_loop :ringring do play tonfolge[tick] sleep 1 end
Die Funktion tick arbeitet wie ein Zähler, die jedesmal – beginnend bei 0 – den aktuellen Wert ausgibt und ihn um 1 erhöht.
Es gibt zwei weitere Artikel zum Thema Ringe auf diesem Blog:
Ringe erzeugen Teil 1
Ringe erzeugen Teil 2
Hat Ihnen dieser Artikel gefallen? Haben Sie einen Fehler gefunden? Ist etwas unklar? Wir freuen uns über Rückmeldungen, Fragen und Anregungen im Kommentarbereich!