Anwendung von Callbackfunktionen in Listen - flutter-tutorial-de/dart-programming GitHub Wiki

Table of Contents

Links

Einfach verständliche Methoden

Folgenden Programmcode können wir in dartpad.dev ausführen:

void say(String prefix, List<String> list){
  print("= $prefix:");
  print(list.join('\n'));
}
void main(){
  final list = ["Dunkel war's", 'der Mond schien helle', 'als ein Auto blitzeschnelle', 'langsam um die runde Ecke fuhr'];
  print('= Das ganze Gedicht:');
  list.forEach(print);
  final filterAU = (String line) => line.contains('a') && line.contains('u');
  print('"a" und "u" kommen zuerst vor in Zeile ' + (1 + list.indexWhere(filterAU)).toString());
  print('"a" und "u" kommen zuletzt vor in Zeile ' + (1 +   list.lastIndexWhere(filterAU)).toString());
  var list2 = list.toList();
  list2.removeWhere((line) => line.contains('z'));
  say('Ohne "z"', list2);
  list2 = list.toList();
  list2.retainWhere((line) => line.length > 25);
  say('Länger als 25 Zeichen', list2);
  print("Erste Zeile mit gerader Wortzahl: " + list.firstWhere((String line) => line.split(' ').length % 2 == 0));
  print("Letzte Zeile mit ungerader Wortzahl: " + list.lastWhere((String line) => line.split(' ').length % 2 == 1, orElse: () => '<nicht gefunden>'));
}
  • list.forEach(print) Die Methode forEach führt die Callbackfunktion für jedes Element aus. In diesem Fall wird print() als Callbackfunktion genutzt. Das passt, da print() als Parameter einen String erwartet.
  • filterAU = (String line) => line.contains('a') && line.contains('u'); Wir definieren eine Filterfunktion als Variable namens filterAU, da dieser Filter dann zweimal gebraucht wird. Die Funktion hat den Parameter line und liefert den Wert true genau dann, wenn in line sowohl 'a' als auch 'u' vorkommen.
  • + (1 + list.indexWhere(filterAU)).toString() Die Methode indexWhere() liefert den ersten Index der Liste, bei der die Testfunktion (hier filterAU) den Wert true liefert. Auf diesen Index wird 1 addiert, da wir die Zeilennummern bei 1 und nicht bei 0 beginnen lassen. Diese Zeilennummer wird dann mit der Methode toString() in einen String gewandelt, der an den String Erste Zeile mit gerader Wortzahl: angehängt werden kann.
  • lastIndexWhere() funktioniert wie indexWhere(), nur dass der letzte Index zurückgeliefert wird.
  • var list2 = list.toList(); Hier erstellen wir eine Kopie namens list2 der Liste list. Das ist nötig, weil wir den Wert von list nicht ändern wollen (und auch nicht können, da final).
  • list2.removeWhere((line) => line.contains('z')); Die Methode removeWhere() löscht diejenigen Elemente, bei der die Testfunktion true liefert.
  • list2.retainWhere((line) => line.length > 25);; Die Methode retainsWhere() lässt alle Elemente unberührt, bei der die Testfunktion true liefert, alle anderen Elemente werden gelöscht.
  • list.firstWhere((String line) => line.split(' ').length % 2 == 0) Die Methode firstWhere liefert das erste Element, für die die Testfunktion true abliefert. Unsere Testfunktion teilt line mittels split(' ') in ein Liste von Wörtern auf, deren Anzahl dann mit der Länge der Liste mittels Attribut length auf "gerade" geprüft wird, mathematisch ob der Rest module 2 gleich der Zahl 0 ist.
  • list.lastWhere((String line) => line.split(' ').length % 2 == 1, orElse: () => '<nicht gefunden>') Die Methode firstWhere liefert das letzte Element, für die die Testfunktion true abliefert. Unsere Testfunktion teilt line mittels split(' ') in eine Liste von Wörtern auf, deren Anzahl dann mit der Länge der Liste mittels Attribut length auf "ungerade" geprüft wird, mathematisch ob der Rest module 2 gleich der Zahl 1 ist. Es wird noch der benannte Parameter orElse benutzt. Der kommt zum Tragen, wenn kein Element gefunden wird. Die Callbackfunktion orElse hat keinen Parameter und muss einen String zurückliefern, in unserem Beispiel nicht gefunden.
Hinweis: Bei den Methoden firstWhere und lastWhere muss sichergestellt sein, dass die Callbackfunktion mindestens einmal true liefert. Wenn nicht, muss die benannte Callbackfunktion orElse angegeben werden.

Sortieren

void main(){
  final list = ["Dunkel war's", 'der Mond schien helle', 'als ein Auto blitzeschnelle', 'langsam um die runde Ecke fuhr'];
  list.sort((String s1, String s2) => s1.split(' ').last.compareTo(s2.split(' ').last));
  print('= Sortiert nach letztem Wort', list.join('\n');
}
  • list.sort((String s1, String s2) => s1.split(' ').last.compareTo(s2.split(' ').last)); Damit sortieren wir die Liste list.
  • Bei der Sortierung finden Vergleiche von jeweils zwei Elementen der Liste statt. Die Callbackfunktion erledigt genau diesen Vergleich.
  • Die Parameter der Callbackfunktion (String s1, String s2) sind also zwei Elemente der Liste.
  • Die Callbackfunktion liefert 0 zurück, wenn die Elemente gleich sind, liefert einen negativen Wert, wenn s1 kleiner als s2 ist und einen positiven Wert, wenn s1 größer als s2 ist.
  • In unserem Beispiel zerlegen wir das Element s1 mittels split(' ') in eine Liste von Wörtern, die Methode last() liefert das letzte Element der Liste. Diesen String vergleichen wir mit der Methode compareTo() mit dem letzten Wort des zweiten Elements s2. compareTo() liefert genau die geforderten Werte ab, 0 für Gleichheit, einen negativen Wert für kleinere und einen positiven Wert für einen größeren Vergleichswert.

Eine Liste aus einer anderen generieren: map()

Oft wollen wir aus einem Feld ein anderes generieren: Beispielsweise haben wir eine Liste von Personen und wollen eine Liste, die genau die Namen der Personen enthält:

class Person {
  final String name;
  final int year;
  Person(this.name, this.year);
}
void main(){
  final persons = [ Person('Huber', 1970), Person('Mayer', 2004), Person('Miller', 1990)];
  final names = persons.map((element) => element.name);
  print('Namen: ' + names.join(' '));
}

Alle Elememente zusammenfassen: fold() und reduce()

  • Die Methode fold() ruft für jedes Element die Callbackfunktion combine() auf.
  • combine() hat zwei Parameter, den vorher berechneten Wert previous und das aktuelle Listenelement element.
  • combine() liefert den daraus berechneten neuen Wert zurück.
  • Der erste Aufruf von combine() beginnt mit dem ersten Parameter von fold().
class Person {
  final String name;
  final int year;
  Person(this.name, this.year);
}
void main(){
  final persons = [ Person('Huber', 1970), Person('Mayer', 2004), Person('Miller', 1990)];
  final sumYears = persons.fold(0, (int previous, Person element) => previous + person.year);
  print('Durchschnittsgeburtsjahr: ${sumYears ~/ persons.length}');
}
  • persons.fold(0, (int previous, Person person) => previous + person.year) Der Anfangswert der Berechnung ist 0 (der erste Parameter von fold().
  • Jeder weitere Wert wird aus dem Vorgängerwert previous und dem Geburtsjahr der aktuellen Person berechnet, nämlich der Summe.
  • sumYears ~/ persons.length Der Durchschnitt berechnet sich aus der Summe dividiert durch die Anzahl, der Listenlänge. Hinweis: ~/ ist Ganzzahldivision.
Die Methode reduce() ist ähnlich, nur dass die Datentypen von previous und element gleich sind, nämlich dem Datentyp eines Listenelements.
  • reduce() benötigt mindestens ein Element in der Liste.
  • reduce(f) ist eine Abkürzung von list.skip(1).fold(list.first, f)
  • reduce() ist viel eingeschränkter als fold()
void main(){
  final data = [ -9, 22, 3, 44, 0 ];
  final sum = data.reduce((int previous, int element) => previous + element);
  print('Summe: $sum');
}
Anmerkung: Die Quadratsumme kann mit reduce() nicht berechnet werden, da der erste Wert dann nicht quadriert wird.
⚠️ **GitHub.com Fallback** ⚠️