Anwendung von Callbackfunktionen in Listen - flutter-tutorial-de/dart-programming GitHub Wiki
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 MethodeforEach
führt die Callbackfunktion für jedes Element aus. In diesem Fall wirdprint()
als Callbackfunktion genutzt. Das passt, daprint()
als Parameter einen String erwartet. -
filterAU = (String line) => line.contains('a') && line.contains('u');
Wir definieren eine Filterfunktion als Variable namensfilterAU
, da dieser Filter dann zweimal gebraucht wird. Die Funktion hat den Parameterline
und liefert den Werttrue
genau dann, wenn inline
sowohl 'a' als auch 'u' vorkommen. -
+ (1 + list.indexWhere(filterAU)).toString()
Die MethodeindexWhere()
liefert den ersten Index der Liste, bei der die Testfunktion (hierfilterAU
) den Werttrue
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 MethodetoString()
in einen String gewandelt, der an den StringErste Zeile mit gerader Wortzahl:
angehängt werden kann. -
lastIndexWhere()
funktioniert wieindexWhere()
, nur dass der letzte Index zurückgeliefert wird. -
var list2 = list.toList();
Hier erstellen wir eine Kopie namenslist2
der Listelist
. Das ist nötig, weil wir den Wert vonlist
nicht ändern wollen (und auch nicht können, da final). -
list2.removeWhere((line) => line.contains('z'));
Die MethoderemoveWhere()
löscht diejenigen Elemente, bei der die Testfunktiontrue
liefert. -
list2.retainWhere((line) => line.length > 25);;
Die MethoderetainsWhere()
lässt alle Elemente unberührt, bei der die Testfunktiontrue
liefert, alle anderen Elemente werden gelöscht. -
list.firstWhere((String line) => line.split(' ').length % 2 == 0)
Die MethodefirstWhere
liefert das erste Element, für die die Testfunktiontrue
abliefert. Unsere Testfunktion teiltline
mittelssplit(' ')
in ein Liste von Wörtern auf, deren Anzahl dann mit der Länge der Liste mittels Attributlength
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 MethodefirstWhere
liefert das letzte Element, für die die Testfunktiontrue
abliefert. Unsere Testfunktion teiltline
mittelssplit(' ')
in eine Liste von Wörtern auf, deren Anzahl dann mit der Länge der Liste mittels Attributlength
auf "ungerade" geprüft wird, mathematisch ob der Rest module 2 gleich der Zahl 1 ist. Es wird noch der benannte ParameterorElse
benutzt. Der kommt zum Tragen, wenn kein Element gefunden wird. Die CallbackfunktionorElse
hat keinen Parameter und muss einen String zurückliefern, in unserem Beispielnicht gefunden
.
firstWhere
und lastWhere
muss sichergestellt sein, dass die Callbackfunktion mindestens einmal true
liefert. Wenn nicht, muss die benannte Callbackfunktion orElse
angegeben werden.
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 Listelist
. - 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 alss2
ist und einen positiven Wert, wenns1
größer alss2
ist. - In unserem Beispiel zerlegen wir das Element
s1
mittelssplit(' ')
in eine Liste von Wörtern, die Methodelast()
liefert das letzte Element der Liste. Diesen String vergleichen wir mit der MethodecompareTo()
mit dem letzten Wort des zweiten Elementss2
.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.
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(' ')); }
- Die Methode
fold()
ruft für jedes Element die Callbackfunktioncombine()
auf. -
combine()
hat zwei Parameter, den vorher berechneten Wertprevious
und das aktuelle Listenelementelement
. -
combine()
liefert den daraus berechneten neuen Wert zurück. - Der erste Aufruf von
combine()
beginnt mit dem ersten Parameter vonfold()
.
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 ist0
(der erste Parameter vonfold()
. - 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.
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 vonlist.skip(1).fold(list.first, f)
-
reduce()
ist viel eingeschränkter alsfold()
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.