Programmiertechnik/Gruppenwechsel
Als Gruppenwechsel (engl. control break) wird der entscheidende Vorgang beim Prinzip der Gruppenkontrolle (häufig auch Gruppenwechsellogik oder Gruppenwechselverarbeitung) bezeichnet. Für die Durchführung eines Gruppenwechsels müssen die Eingabedaten nach dem Gruppenkriterium sortiert[1] vorliegen und sequentiell verarbeitet werden. Der Gruppenwechsel wird durchgeführt, wenn der gerade zu verarbeitende Datensatz einer anderen Gruppe zugehörig ist als der unmittelbar zuvor verarbeitete Datensatz.
Unterschieden werden einstufige und mehrstufige Gruppenwechsel. Bei einem einstufigen Gruppenwechsel hängt eine Gruppe von nur einem einzigen Gruppenbezeichner ab (Gruppenwechsel 1. Ordnung). Bei mehrstufigen Gruppenwechseln hängt die Zugehörigkeit eines Datensatzes zu einer (Unter-) Gruppe von zwei oder mehr Kriterien ab (Gruppenwechsel 2. bis n. Ordnung).
Inhaltsverzeichnis
Vorgehensweise
Grundsätzlich gliedert sich die Vorgehensweise zur Durchführung eines Gruppenwechsels in die drei Schritte Gruppenvorlauf, Gruppendurchlauf und Gruppennachlauf. Zuvor kann eine Initialisierung und anschließend eine Nachbearbeitung stattfinden. Der eigentliche Gruppenwechsel findet implizit nach dem Gruppennachlauf statt, d. h. die Gruppe wird durch die vorgelagerten Schritte bereits gewechselt, ohne dass der Wechsel selbst noch explizit angegeben werden muss (vgl. die folgenden Ausführungen).
Ein mehrstufiger Gruppenwechsel besteht aus mehreren, ineinander verschachtelten, einstufigen Gruppenwechseln, d. h. innerhalb des Gruppendurchlaufs der Obergruppe finden zusätzlich die drei Schritte Vor-, Durch- und Nachlauf der Untergruppe statt. Dies lässt sich beliebig oft wiederholen (bzw. beliebig tief verschachteln).
Die einzelnen Schritte zur Durchführung einer Gruppenkontrolle werden im Folgenden beschrieben. Zum besseren Verständnis des Geschriebenen folgen anschließend einige Beispiele.
Information
Initialisierung
In der Initialisierungsphase werden beispielsweise generelle, d. h. für alle (Unter-)Gruppen bzw. alle Elemente gültige Variablen initialisiert. So werden u. a. Zählervariablen für die spätere Ausgabe einer Summenzeile hier initialisiert. Erfolgt eine Ausgabe von tabellarischen Daten könnte beispielsweise der Tabellenkopf während der Initialisierungsphase ausgegeben werden.
Gruppenvorlauf
Im Unterschied zur Initialisierung werden beim Gruppenvorlauf z. B. spezifische, also die gerade durchlaufene Gruppe betreffende Variablen initialisiert. Dies können Zählervariablen sein, wenn z. B. später eine Summe für die einzelne Gruppe ausgegeben werden soll. Bei einer direkten Ausgabe könnte im Gruppenvorlauf auch der Name der Gruppe oder ähnliches ausgegeben werden.
Gruppendurchlauf
Der Gruppendurchlauf erfolgt solange, bis "das Ende" einer Gruppe erreicht wurde. Dies ist der Fall, wenn der aktuell verarbeitete Datensatz einer anderen Gruppe als der vorherige Datensatz angehört oder es sich um den letzten Datensatz handelt. Dann folgt der Gruppennachlauf. Ansonsten werden im Gruppendurchlauf z. B. die generellen und spezifischen Zählervariablen erhöht oder – im Falle einer Ausgabe – zum Beispiel der Name des Elements ausgegeben.
Gruppennachlauf
Der Gruppennachlauf folgt auf das letzte Element der aktuell verarbeiteten Gruppe. Hier kann beispielsweise eine Summenzeile für die aktuell verarbeitete Gruppe ausgegeben werden.
Nachbearbeitung
Die Nachbearbeitung folgt auf das letzte verarbeitete Element. Die Nachbearbeitung ist ähnlich dem Gruppennachlauf, nur dass hier beispielsweise die während der Initialisierung angelegten Variablen als Gesamtsumme aller Elemente ausgegeben werden können.
Vollständige Vorgehensweise
Wie die Gruppenkontrolle konkret umgesetzt wird hängt grundsätzlich von den vorliegenden Daten und der verwendeten Programmiersprache, sprich vom konkreten Anwendungsfall, ab. Die prinzipielle Vorgehensweise ähnelt sich aber. Im Nebenstehenden UML-Aktivitätsdiagramm ist die entscheidende Programmlogik für die sequentielle Datenverarbeitung bei einem einstufigen Gruppenwechsel dargestellt.
Im Folgenden der Pseudocode für einen einstufigen Gruppenwechsel:
- Hole die zu verarbeitenden Daten
- Sortiere[1] die Daten entsprechend des Gruppenkriteriums
- Initialisiere eine Variable namens GRUPPE mit dem Wert NULL
- Durchlaufe alle Datensätze
- Wenn die Gruppe des aktuell verarbeiteten Datensatzes ungleich der GRUPPE ist
- Setze den Wert der Variable GRUPPE gleich der Gruppe des aktuell verarbeiteten Datensatzes
- Wenn die Gruppe des aktuell verarbeiteten Datensatzes ungleich der GRUPPE ist
- KOMMENTAR: Aktuell verarbeiteter Datensatz gehört der Gruppe GRUPPE an
Der Pseudocode für einen zweistufigen Gruppenwechsel:
- Hole die zu verarbeitenden Daten
- Sortiere[1] die Daten entsprechend des Gruppen- und des Untergruppenkriteriums
- Initialisiere eine Variable namens GRUPPE mit dem Wert NULL
- Initialisiere eine Variable namens UNTERGRUPPE mit dem Wert NULL
- Durchlaufe alle Datensätze
- Wenn die Gruppe des aktuell verarbeiteten Datensatzes ungleich der GRUPPE ist
- Setze den Wert der Variable GRUPPE gleich der Gruppe des aktuell verarbeiteten Datensatzes
- Setze den Wert der Variable UNTERGRUPPE gleich der Untergruppe des aktuell verarbeiteten Datensatzes
- Wenn die Untergruppe des aktuell verarbeiteten Datensatzes ungleich der UNTERGRUPPE ist
- Setze den Wert der Variable UNTERGRUPPE gleich der Untergruppe des aktuell verarbeiteten Datensatzes
- Wenn die Gruppe des aktuell verarbeiteten Datensatzes ungleich der GRUPPE ist
- KOMMENTAR: Aktuell verarbeiteter Datensatz gehört der Gruppe GRUPPE und der Untergruppe UNTERGRUPPE an
Beispiele
Im Folgenden werden einige Beispiele für Gruppenwechsel dargestellt. Die generelle Vorgehensweise kann auf andere Probleme übertragen werden.
Allgemein
Allgemeine Beispiele die (hoffentlich) das Prinzip des Gruppenwechsels anschaulich erklären.
Bahnreisender
Ein Bahnreisender möchte mit dem ICE von Hamburg nach München reisen. Da er in Eile war hatte er vergessen auf den Fahrplan zu schauen. Er möchte aber gerne wissen, welche und wie viele Bahnhöfe der Zug in welchem Bundesland und insgesamt anfährt. Obwohl er gut in Geografie ist, kann er sich andere Dinge schlecht merken und rechnen ist auch nicht unbedingt seine Stärke. Glücklicherweise hat er aber trotz der Eile an sein Notizbuch gedacht und es eingepackt.
Er steigt in den Zug ein und fasst den Plan, einfach alles in sein Notizbuch zu schreiben um am Ende der Reise trotzdem zu wissen, welche Route der Zug gefahren ist. Zuerst schlägt er eine neue Seite seines Notizbuches auf und schreibt oben dick Anzahl Bahnhöfe hin. Bei jedem Bahnhof, an dem der Zug hält, wird er hier einen Strich machen. So braucht er am Ende nur die Striche abzählen und weiß, wie viele Bahnhöfe der Zug insgesamt angefahren ist.
Darunter malt er ein großes Kästchen. Hier wird er immer das Bundesland reinschreiben, in dem er sich gerade befindet. Gut, das er aus Gewohnheit immer mit Bleistift schreibt, so kann er das Kästchen immer wieder ausradieren, wenn er in ein neues Bundesland kommt.
Auf der restlichen Notizbuchseite hat er nun genug Platz, um die einzelnen Bahnhöfe und Bundesländer aufzuschreiben. Er wird immer, wenn der Zug an einem Bahnhof eines anderen Bundeslandes ankommt (dann hat er also offensichtlich das letzte Bundesland verlassen, so überlegt er sich) das neue Bundesland aufschreiben und darunter einfach immer die Bahnhöfe, an denen der Zug hält. Das Bundesland wird er zudem unterstreichen, damit er auf einen Blick sieht, dass es sich dabei um ein Bundesland und keinen Bahnhof handelt. Und daneben wird er bei jedem Halt einen Strich machen, so braucht er auch hier später nur die Striche zählen und weiß, wie viele Bahnhöfe der Zug in diesem Bundesland angefahren hat.
"Die Fahrt kann also beginnen!", denkt sich der Bahnreisende, bevor er doch noch einmal kurz seinen Plan überdenkt: Er möchte eigentlich alle Bahnhöfe auflisten. Bei seinem Prinzip hatte er aber ganz vergessen, dass er bereits in den Zug eingestiegen ist und sich im Hamburger Bahnhof befindet. Er macht also schnell einen Strich hinter Anzahl Bahnhöfe. Außerdem schreibt er in das große Kästchen Hamburg, da er sich gerade im Bundesland Hamburg befindet. Und unter das Kästchen schreibt er Hamburg (das Bundesland) und unterstreicht es, macht einen Strich dahinter (da dies der erste Bahnhof im Bundesland Hamburg ist) und schreibt darunter Hamburg Hbf, also seinen Einsteigebahnhof.
Der Zug setzt sich in Bewegung und stoppt schon kurze Zeit später in Hamburg-Harburg. Der Bahnreisende befindet sich offentsichtlich noch in Hamburg und macht daher einen Strich neben Hamburg. Außerdem zeichnet er einen Strich neben Anzahl Bahnhöfe und den schreibt den Namen des Bahnhofs, hier also Hamburg-Harburg an das Ende seiner Liste. Da er dies bei jedem Halt macht, wird er es in dieser Geschichte nicht weiter erwähnen. Der Zug fährt weiter.
Nächster Halt: Hannover Hbf. Der Bahnreisende weiß, dass er sich jetzt in der Landeshauptstadt Niedersachsens befindet. Er blickt auf sein Notizbuch und sieht, dass in dem großen Kästchen oben auf der Seite aber Hamburg steht. Er muss somit Hamburg verlassen haben und nun in Niedersachsen angekommen sein. Daher schreibt er nun Niedersachsen auf seinen Notizzettel, unterstreicht es und malt gleichzeitig wieder einen Strich daneben. Zudem radiert er Hamburg aus dem Kasten oben auf der Seite aus und schreibt stattdessen Niedersachsen hinein.
Als nächstes hält der Zug in Göttingen. Hier macht der Bahnreisende sowohl einen Strich bei Anzahl Bahnhöfe als auch neben Niedersachsen und schreibt zudem Göttingen an das Ende seiner Notizen. Bis er in München ankommt macht er also immer wieder das Gleiche wie zuvor beschrieben: Bei jedem Bahnhof macht er einen Strich neben Anzahl Bahnhöfe. Sollte er sich noch immer im selben Bundesland wie zuvor befinden schreibt er einen Strich neben das Bundesland. Wenn er merkt, dass er ein Bundesland verlassen hat, schreibt er den Namen des "neuen" Bundeslandes in das Kästchen. Außerdem schreibt er es in diesem Fall an das Ende seiner Notizen und unterstreicht es. Zuletzt schreibt er den Namen des Bahnhofs an das Ende seiner Notizen.
Der Zug fährt in München Hbf ein, das Ende seiner Reise. Der Bahnreisende kann nun nach einem kurzen Blick auf seinen Notizzettel seinen Freunden, die dort bereits auf ihn warten, erzählen, wie seine Bahnreise verlief:
JavaScript
Beispiele für Gruppenwechsel in JavaScript.
Länder und Kontinente (1. Ordnung)
In einem bereits existierenden HTML-Dokument sollen die Länder nach Kontinenten gruppiert farbig markiert werden. Die Länder und zugehörigen Kontinente liegen nach dem Gruppenkriterium sortiert[1] in einer HTML-Tabelle ähnlich der folgenden Darstellung vor:
Land | Kontinent |
---|---|
Algerien | Afrika |
Nigeria | Afrika |
Seychellen | Afrika |
Indien | Asien |
Indonesien | Asien |
Volksrepublik China | Asien |
Australien | Australien / Ozeanien |
Nauru | Australien / Ozeanien |
Neuseeland | Australien / Ozeanien |
Deutschland | Europa |
Frankreich | Europa |
Vereinigtes Königreich | Europa |
Kanada | Nordamerika |
Mexico | Nordamerika |
Vereinigte Staaten | Nordamerika |
Argentinien | Südamerika |
Brasilien | Südamerika |
Peru | Südamerika |
// Hex-Farbcodes zum Einfärben der Tabellenzeilen
var farben = ['#FED52E', '#F33E01', '#C04080', '#C10000', '#00CC00', '#008000'];
// Die Tabellenzeilen der Tabelle holen
var laender = document.querySelectorAll('tbody tr');
// Gruppenvariable "Kontinent" initialisieren
var kontinent = null;
// Den Zähler, welche Farbe gerade verwendet wird, initialisieren
var farbZaehler = -1;
// Die Tabellenzeilen durchlaufen
for (var i = 0; i < laender.length; i++) {
// Tabellenzellen der Zeile holen; das entspricht einem Tabelleneintrag
var eintrag = laender[i].querySelectorAll('td');
// Prüfen, ob es sich um den ersten Durchlauf handelt oder das aktuelle Land
// einem anderen Kontinent als das vorherige Land angehört
// (das ist der eigentliche Gruppenwechsel)
if (i == 0 || kontinent != eintrag[1].innerHTML) {
// Den aktuellen Kontinent als Gruppenvariable setzen
kontinent = eintrag[1].innerHTML;
// Die Farbe wechseln; dies ist die Farbe für diesen und für alle
// zukünftigen Einträge dieser Gruppe
farbZaehler++;
}
// Gruppendurchlauf: Die Tabellenzelle mit der aktuellen Gruppenfarbe
// einfärben
laender[i].style.backgroundColor = farben[farbZaehler];
}
PHP
Beispiele für Gruppenwechsel in PHP.
Tierarten (1. Ordnung)
In zwei normalisierten Datenbanktabellen sind Tiere sowie die "Tierart", der sie angehören, aufgeführt:
ID | Name |
---|---|
1 | Vögel |
2 | Säugetiere |
Tierart-ID | Name |
---|---|
1 | Amsel |
1 | Drossel |
1 | Fink |
1 | Star |
2 | Hund |
2 | Katze |
2 | Maus |
2 | Elefant |
Die Tiere sollen nun nach "Tierarten" gruppiert ausgegeben werden. Dazu wird eine Datenbank-Abfrage gestartet, welche mit Hilfe von Joins die Daten nach dem Gruppenkriterium "Tierart" sortiert[1] zur Verfügung stellt. Die resultierende Tabelle (und damit das resultierende PHP-Array) ist somit:
Tierart | Name |
---|---|
Säugetiere | Elefant |
Säugetiere | Hund |
Säugetiere | Katze |
Säugetiere | Maus |
Vögel | Amsel |
Vögel | Drossel |
Vögel | Fink |
Vögel | Star |
// Die sortierten Daten aus der Datenbank holen
$tiere = [/*...*/];
// Tierart (Gruppe) initialisieren
$tierart = null;
// Das Array mit den Tieren durchlaufen
foreach ($tiere as $tier) {
// $tier ist ein assoziatives Array:
// $tier = array('tierart' => 'Name der Tierart', 'name' => 'Name des Tieres')
// Prüfen, ob das Tier einer anderen Tierart als das Tier zuvor angehört;
// das ist der eigentliche Gruppenwechsel
if ($tierart != $tier['tierart']) {
// Aktuellen Gruppennamen (die Tierart) merken
$tierart = $tier['tierart'];
// Die Gruppe (Tierart) als Überschrift ausgeben
printf('<h1>%s</h1>', $tierart);
}
// Den Tiernamen ausgeben
printf('<p>%s</p>', $tier['name']);
}
Schüler einer Klasse (2. Ordnung)
In drei normalisierten Datenbanktabellen sind Schulen, zugehörige Klassen sowie die Schüler, die eine Klasse besuchen, aufgelistet:
Schul-ID | Name |
---|---|
1 | Albert-Schweitzer-Schule |
2 | Geschwister-Scholl-Schule |
Klassen-ID | Schul-ID | Name |
---|---|---|
1 | 1 | 1 |
2 | 1 | 2 |
3 | 2 | 1 |
4 | 2 | 2 |
5 | 2 | 3 |
6 | 2 | 4 |
Klassen-ID | Name |
---|---|
1 | Elias |
1 | Emily |
1 | Finn |
1 | Lea |
2 | Lena |
2 | Luca |
2 | Marie |
2 | Noah |
3 | Anna |
3 | Ben |
4 | Emilia |
4 | Emma |
4 | Hannah |
4 | Jonas |
5 | Leon |
5 | Luis |
5 | Lukas |
6 | Mia |
6 | Paul |
6 | Sophia |
Die Schüler sollen nun nach Schule und Klasse gruppiert ausgegeben werden. Außerdem soll die Anzahl der Schüler einer Schule ausgegeben werden. Dazu wird zuerst eine Datenbank-Abfrage gestartet, welche mit Hilfe von Joins die Daten nach den Gruppenkriterien "Schule" und "Klasse" sortiert[1] zur Verfügung stellt. Die resultierende Tabelle (und damit das resultierende PHP-Array) ist somit:
Schule | Klasse | Name |
---|---|---|
Albert-Schweitzer-Schule | 1 | Elias |
Albert-Schweitzer-Schule | 1 | Emily |
Albert-Schweitzer-Schule | 1 | Finn |
Albert-Schweitzer-Schule | 1 | Lea |
Albert-Schweitzer-Schule | 2 | Lena |
Albert-Schweitzer-Schule | 2 | Luca |
Albert-Schweitzer-Schule | 2 | Marie |
Albert-Schweitzer-Schule | 2 | Noah |
Geschwister-Scholl-Schule | 1 | Anna |
Geschwister-Scholl-Schule | 1 | Ben |
Geschwister-Scholl-Schule | 2 | Emilia |
Geschwister-Scholl-Schule | 2 | Emma |
Geschwister-Scholl-Schule | 2 | Hannah |
Geschwister-Scholl-Schule | 2 | Jonas |
Geschwister-Scholl-Schule | 3 | Leon |
Geschwister-Scholl-Schule | 3 | Luis |
Geschwister-Scholl-Schule | 3 | Lukas |
Geschwister-Scholl-Schule | 4 | Mia |
Geschwister-Scholl-Schule | 4 | Paul |
Geschwister-Scholl-Schule | 4 | Sofia |
// Die sortierten Daten aus der Datenbank holen
$schueler = [/*...*/];
// Schule (Hauptgruppe) initialisieren
$schule = null;
// Zählvariable für die Anzahl der Schüler einer Schule
$anzahlSchueler = 0;
// Klasse (Nebengruppe) initialisieren
$klasse = null;
// Die Schüler der aktuell verarbeiteten Klasse als Array initialisieren
$schuelerDerKlasse = [];
// Das Array mit den Schülern durchlaufen
foreach ($schueler as $einSchueler) {
// $einSchueler ist ein assoziatives Array:
// $einSchueler = [
// 'schule' => 'Name der Schule',
// 'klasse' => 'Welcher Klasse der Schüler zugehört',
// 'name' => 'Name des Schülers',
// ]
// Prüfen, ob der aktuelle Schüler eine andere Klasse als der Schüler
// aus dem letzten Schleifendurchlauf besucht; das ist der Gruppenwechsel
// der Nebengruppe
if ($einSchueler['klasse'] != $klasse) {
// Der Schüler besucht eine andere Klasse als der zuletzt verarbeitete
// Schüler
// Die Klasse und die zugehörigen Schüler ausgeben, falls dies nicht der
// erste Schleifendurchlauf ist; dies ist der Gruppennachlauf der
// Nebengruppe
if ($klasse !== null) {
printf('<p>Klasse %d: %s</p>', $klasse, implode(', ', $schuelerDerKlasse));
}
// Den neuen Nebengruppennamen (die Klasse des aktuellen Schülers)
// merken, hier beginnt der Gruppenvorlauf der Nebengruppe
$klasse = $einSchueler['klasse'];
// Das Array mit den Schülern einer Klasse zurücksetzen
$schuelerDerKlasse = [];
}
// Prüfen, ob der aktuelle Schüler eine andere Schule als der Schüler
// aus dem letzten Schleifendurchlauf besucht; das ist der eigentliche
// Gruppenwechsel
if ($einSchueler['schule'] != $schule) {
// Der Schüler besucht eine andere Schule als der zuletzt verarbeitete
// Schüler
// Die Anzahl der Schüler der Schule ausgeben, falls dies nicht der
// erste Schleifendurchlauf ist; dies ist der Gruppennachlauf der
// Hauptgruppe
if ($schule !== null) {
printf('<p>%d Schüler besuchen die %s.</p>', $anzahlSchueler, $schule);
}
// Den neuen Gruppennamen (die Schule des aktuellen Schülers) merken;
// hier beginnt der Gruppenvorlauf der Hauptgruppe
$schule = $einSchueler['schule'];
// Den Zähler für die Anzahl der Schüler zurücksetzen
$anzahlSchueler = 0;
// Den Namen der Schule ausgeben
printf('<h1>%s</h1>', $schule);
}
// Den Namen des Schülers merken, da er die aktuell verarbeitete Klasse
// besucht (das ist der Gruppendurchlauf der Nebengruppe)
$schuelerDerKlasse[] = $einSchueler['name'];
// Den Zähler für die Anzahl der Schüler einer Schule um 1 erhöhen
// (das ist der Gruppendurchlauf der Hauptgruppe)
$anzahlSchueler++;
}
// Die Nachbearbeitung: Für die letzte Schule und die letzte Klasse muss noch,
// ähnlich dem Gruppennachlauf, eine Ausgabe generiert werden
printf('<p>Klasse %d: %s</p>', $klasse, implode(', ', $schuelerDerKlasse));
printf('<p>%d Schüler besuchen die %s.</p>', $anzahlSchueler, $schule);
Forumsbeiträge (3. Ordnung)
In einer Datenbanktabelle sind Forenbeiträge ähnlich der folgenden Tabelle gespeichert:
Beitrag-ID | Datum | Autor-ID | Beitrag |
---|---|---|---|
1 | 2015-11-11 | ... | ... |
2 | 2015-11-12 | ... | ... |
3 | 2015-11-12 | ... | ... |
... | ... | ... | ... |
31 | 2016-01-03 | ... | ... |
Mit Hilfe der Gruppenwechsellogik soll nun die Anzahl der Beiträge eines Jahres, eines Monats und eines Tags ermittelt und in einer ungeordneten Liste ausgegeben werden. Darüber hinaus sollen Zählung (die Verarbeitung der Datensätze) und Ausgabe separiert werden (vgl. EVA-Prinzip).
// Die nach Datum sortierten Beiträge aus der Datenbank holen
$beitraege = [/*...*/];
// Initialisierung: Die Gruppenvariablen initialisieren
$gruppe = [
'jahr' => ['wert' => null, 'anzahl' => 0],
'monat' => ['wert' => null, 'anzahl' => 0],
'tag' => ['wert' => null, 'anzahl' => 0],
];
// Die Zeitfunktionen für die spätere Ausgabe auf "deutsch" einstellen
// (vgl. dazu den Kommentar weiter unten bei "DateTime")
setlocale(LC_TIME, 'de_DE', 'de', 'deu', 'german');
// Das Datenarray für die Ausgabe initialisieren
$ausgabe = [];
// Arrays zum Zwischenspeichern von Monaten und Tagen initialisieren
$monate = [];
$tage = [];
// Alle Beiträge durchlaufen
foreach ($beitraege as $index => $beitrag) {
// Das Beitragsdatum in ein DateTime-Objekt "umwandeln" (das muss nicht
// unbedingt gemacht werden, es schadet aber auch nicht; insgesamt ist es
// guter Stil, Objekte wie DateTime zu verwenden, da sie wie in diesem Fall
// später Arbeit sparen; hier wird durch das Verwenden des Objekts das
// parsen des Datums "gespart" und die spätere Ausgabe erleichtert)
$datum = new DateTime($beitrag['datum']);
// Datumsvariablen initialisieren
$tag = $datum->format('d.m.Y');
$monat = strftime('%B', $datum->getTimestamp());
$jahr = $datum->format('Y');
// Prüfen, ob Beitragstag, -monat oder -jahr dieses Beitrags anders als
// beim vorherigen Beitrag sind
if ($gruppe['tag']['wert'] != $tag
|| $gruppe['monat']['wert'] != $monat
|| $gruppe['jahr']['wert'] != $jahr
) {
// Prüfen, ob es sich nicht um den ersten Gruppendurchlauf handelt
if ($index != 0) {
// Gruppennachlauf 3. Gruppe: Den Tag in den Tagzwischenspeicher
// schreiben
$tage[] = [
'wert' => $gruppe['tag']['wert'],
'anzahl' => $gruppe['tag']['anzahl']
];
}
// Gruppenvorlauf 3. Gruppe: Den aktuellen Tag als Gruppenvariable
// setzen und den Beitragszähler zurücksetzen
$gruppe['tag']['wert'] = $tag;
$gruppe['tag']['anzahl'] = 0;
}
// Prüfen, ob Beitragsmonat oder -jahr dieses Beitrags anders als beim
// vorherigen Beitrag sind
if ($gruppe['monat']['wert'] != $monat
|| $gruppe['jahr']['wert'] != $jahr
) {
// Prüfen, ob es sich nicht um den ersten Gruppendurchlauf handelt
if ($index != 0) {
// Gruppennachlauf 2. Gruppe: Den Monat in den Monatszwischen-
// speicher schreiben
$monate[] = [
'wert' => $gruppe['monat']['wert'],
'anzahl' => $gruppe['monat']['anzahl'],
'tage' => $tage
];
}
// Gruppenvorlauf 2. Gruppe: Den aktuellen Monat als Gruppenvariable
// setzen und den Beitragszähler sowie den Zwischenspeicher zurücksetzen
$gruppe['monat']['wert'] = $monat;
$gruppe['monat']['anzahl'] = 0;
$tage = [];
}
// Prüfen, ob das Beitragsjahr dieses Beitrags ein anderes als das des
// vorherigen Beitrags ist
if ($gruppe['jahr']['wert'] != $jahr) {
// Prüfen, ob es sich nicht um den ersten Gruppendurchlauf handelt
if ($index != 0) {
// Gruppennachlauf 1. Gruppe: Das Jahr in die Ausgabedaten schreiben
$ausgabe[] = [
'wert' => $gruppe['jahr']['wert'],
'anzahl' => $gruppe['jahr']['anzahl'],
'monate' => $monate
];
}
// Gruppenvorlauf 1. Gruppe: Das aktuelle Jahr als Gruppenvariable
// setzen und den Beitragszähler sowie den Zwischenspeicher zurücksetzen
$gruppe['jahr']['wert'] = $jahr;
$gruppe['jahr']['anzahl'] = 0;
$monate = [];
}
// Gruppendurchlauf: Die Beitragszähler um 1 erhöhen
$gruppe['jahr']['anzahl']++;
$gruppe['monat']['anzahl']++;
$gruppe['tag']['anzahl']++;
}
// Nachbearbeitung Tage: Die letzte Gruppe in die Ausgabedaten schreiben
$tage[] = [
'wert' => $gruppe['tag']['wert'],
'anzahl' => $gruppe['tag']['anzahl'],
];
// Nachbearbeitung Monate: Die letzte Gruppe in die Ausgabedaten schreiben
$monate[] = [
'wert' => $gruppe['monat']['wert'],
'anzahl' => $gruppe['monat']['anzahl'],
'tage' => $tage
];
// Nachbearbeitung Jahre: Die letzte Gruppe in die Ausgabedaten schreiben
$ausgabe[] = [
'wert' => $gruppe['jahr']['wert'],
'anzahl' => $gruppe['jahr']['anzahl'],
'monate' => $monate
];
// Die Jahre als Liste ausgeben
echo '<ul>';
foreach ($ausgabe as $jahr) {
echo '<li>';
printf('%s (%d)', $jahr['wert'], $jahr['anzahl']);
// Die Monate als Liste ausgeben
echo '<ul>';
foreach ($jahr['monate'] as $monat) {
echo '<li>';
printf('%s (%d)', $monat['wert'], $monat['anzahl']);
// Die Tage als Liste ausgeben
echo '<ul>';
foreach ($monat['tage'] as $tag) {
echo '<li>';
printf('%s (%d)', $tag['wert'], $tag['anzahl']);
echo '</li>';
}
echo '</ul>';
echo '</li>';
}
echo '</ul>';
echo '</li>';
}
echo '</ul>';
Besser ist es somit etwas wie
<p><?= $var ?></p>
statt
<?php echo '<p>' . $var . '</p>' ?>
FAQ - Häufig gestellte Fragen
Im folgenden werden einige Hinweise zum Gruppenwechsel gegeben.
Wann verwende ich einen Gruppenwechsel?
Das Gruppenwechsel-Prinzip wird immer dann verwendet, wenn Daten sequentiell vorliegen (dies ist z. B. meistens bei der Datenhaltung in einer Datenbank der Fall) und nach einer oder mehreren Eigenschaften gruppiert ausgegeben werden sollen.
Was sind die Voraussetzungen für einen Gruppenwechsel?
Die Hauptvoraussetzungen für eine Gruppenwechsel sind, dass die Daten anhand eines oder mehrerer Eigenschaften gruppierbar sind und zudem nach diesen Gruppenkriterien sortiert[1] vorliegen.
Wo sind die Grenzen des Gruppenwechsels?
Wenn die Voraussetzungen für einen Gruppenwechsel gegeben sind gibt es keine Einschränkungen. Allerdings wird ein "klassischer" Gruppenwechsel mit mehr als ca. drei Gruppierungskriterien sehr unübersichtlich. Es bieten sich bei mehreren Eigenschaften, nach den gruppiert werden soll, häufig alternative Vorgehensweisen an.
Was sind Alternativen zum Gruppenwechsel?
Das hängt ganz vom speziellen Anwendungsfall ab. Häufig bieten Funktionen oder Rekursion weitere Möglichkeiten. Zudem besitzen einige Programmiersprachen mächtige Werkzeuge, die einen Gruppenwechsel indirekt ermöglichen (bspw. sind Arrays in PHP sehr mächtig und können im Einzelfall einen expliziten Gruppenwechsel ersetzen).
Hilfe, das geht nicht!
Dass der Gruppenwechsel "nicht funktioniert" kann viele Ursachen haben. Hier ein mögliches Vorgehen zur Fehlersuche:
- Debugging, Debugging, Debugging!
- Überprüfen, ob die Daten überhaupt anhand eines oder mehrerer Kriterien gruppiert werden können
- Überprüfen, ob die Daten nach dem Gruppenkriterium sortiert[1] vorliegen
- Überprüfen, ob die Daten der Reihe nach verarbeitet werden
- Die Reihenfolge der einzelnen Schritte (Vorlauf – Durchlauf – Nachlauf, vgl. Vorgehensweise) überprüfen, insbesondere bei mehreren Kriterien kann hier schnell einiges durcheinander kommen
- Falls die erste oder letzte Gruppe nicht richtig verarbeitet wird:
- Variableninitialisierung prüfen
- Prüfen, ob die letzte(n) Gruppe(n) (nochmal) abschließend behandelt werden
- Im SelfHTML-Forum nach Hilfe fragen
Weblinks
Fußnoten
- ↑ 1,0 1,1 1,2 1,3 1,4 1,5 1,6 1,7 Sortierung bedeutet in diesem Zusammenhang, dass die zur selben Gruppe gehörenden Datensätze direkt aufeinanderfolgend vorliegen. Die Datensätze müssen darüber hinaus nicht weiter sortiert werden, bspw. ist eine Sortierung von A-Z, 0-9 oder Vergleichbares nicht nötig.
- ↑ Fahrtverlauf des ICE 681 (15. September 2015)
- ↑ Zum Zeitpunkt der Beitragserstellung (2015) die häufigsten Schulnamen in Deutschland
- ↑ Zum Zeitpunkt der Beitragserstellung (2015) die beliebtesten Vornamen in Deutschland