Scala Grundkurs

Listentypen

LinkedIn Learning kostenlos und unverbindlich testen!

Jetzt testen Alle Abonnements anzeigen
Ziel einer Programmierung ist meist die Datenverarbeitung und dabei hat man häufig mit Listen zu tun. Scala selbst definiert eigene Typen für Listen. Dazu gehören zum Beispiel die Typen List, Queue, Sequence und Vector, die Ihnen in diesem Video näher vorgestellt werden.

Transkript

Üblicherweise ist das Ziel der Programmierung die Datenverarbeitung. Und als solches hat man oftmals mit Listen zu tun. Schließlich verarbeitet man nicht nur einen einzigen Datensatz. Die Programmiersprache Java als Solches bringt bereits viele mögliche Implementierungen für die Arbeit mit solchen Datensätzen mit sich. Doch Scala, beziehungsweise das Projekt rund um Scala hat sich dafür entscheiden, Listentypen noch einmal selbstständig für die Scala-Programmiersprache zu implementieren. Und genau diese Listentypen werde ich Ihnen nun demonstrieren. Ich befinde mich also hier in meiner Applikation. Innerhalb dieser Applikation kann ich Produkte pflegen. Beispielsweise ein Nintendo Switch-Gerät oder ein Galaxy S6 Smartphone. Mein Ziel ist es jetzt also, genau diese drei Datensätze mithilfe von Listen zusammenzufassen. Wenn ich eine Liste in Scala erzeuge, und diese eine immutable list ist, so wie standardmäßig, sollte ich auf jeden Fall eine Variable verwenden, insofern ich noch plane die Liste beispielsweise zu erweitern. Ich nenne meine Liste also nun "productList" und initialisiere sie mithilfe von "List.empty" und spezifiziere zusätzlich noch den Typ "Product". Eine Liste könnte man als leere Liste theoretisch auch so initialisieren, dass man einfach offene und geschlossene Klammer als Syntax angibt. Allerdings erzeugt dies ein neues Listenobjekt, während ein "empty"-Listenobjekt initial bei der Applikation nur einmal erzeugt wird. so dass eine leere Liste nicht mehrfach existieren muss. Man sollte also aus Speichereffizienzgründen, wenn man kann, immer "list.empty" initial verwenden. Auf dieser Liste gibt es dann noch beispielsweise Hilfsfunktionen. Eine davon ist die Überprüfung, ob die Liste leer ist. Dies kann ich zum Beispiel tun, mit "prductList.IsEmpty" In dem Fall ist meine Liste als nun noch leer. Nun habe ich verschiedene Möglichkeiten, meine Liste zu erweitern. Eine Möglichkeit ist der sogenannte prepend. Bei dem weiß ich also nun, eine neue Instanz meiner Variable "productList" zu, in dem ich ein Produkt nehme, beispielsweise "product1", und das Ganze per prepend vor die "productList" stelle. Zu dieser Syntax gibt es auch noch eine Alternative. Ich kann das Ganze deutlich kompakter darstellen, indem ich beispielsweise nun mein product nehme, also "product1", und die doppelte Doppelpunktnotation vor das "=" schreibe. Dann wird also automatisch der productList die neue Instanz der Liste zugewiesen. Das bedeutet auch also, dass ich mit jeder dieser Aktionen immer eine neue Liste erzeuge. Ich kann meine Liste auch beispielsweise um andere Listen erweitern; in dem Fall mache ich also eine Liste, die ich nun für diesen Zweck nur initialisiere, die beispielsweise das product2 beinhaltet. Als Nächstes füge ich noch das product Nummer 3 hinzu. Nun nutze ich eine weitere Hilfsmethode. Beispielsweise kann ich das erste Element einer Liste bestimmen, in dem Fall also "productList.head". Alternativ könnte ich auch "productList.last" schreiben, dann würde ich entsprechend das letzte Element erhalten. Interessant ist an der Stelle, dass das IPad Pro nun das erste Element in der Liste ist. Das IPad Pro ist allerdings das product Nummer 3. Dadurch, dass wir aber einen prepend durchführen, wird also das zuletzt hinzugefügte Element immer am Anfang der Liste sein. Der Grund hierfür sind Performance-Charakteristiken. Denn das Hinzufügen eines Elements am Anfang der Liste ist bei einer linked List, also der Implementierung der Liste innerhalb von Scala, deutlich effizienter. Wenn ich es wünschen würde, könnte ich tatsächlich allerdings auch ein Produkt hinten an die Liste hinzfügen. Dies ist aber mit einer Komplexität verbunden, die der Länge der aktuellen Liste entspricht, da quasi die gesamte Liste zunächst einmal durchforstet werden muss. Die Syntax hierfür ist, statt doppeltem Doppelpunkt, "+" nach dem Doppelpunkt "=". Und dann könnte ich beispielsweise product1 hinzufügen. In der product.List äußert sich das dann so, dass ich nun eine Nintendo Switch am Ende der Liste habe. Die Liste ist wohl der häufigste Datentyp, den man verwenden wird. Alternativ gibt es auch noch eine Sequence. Eine Sequence an und für sich ist eine ReadOnly-Datenstruktur. DAs bedeutet ich kann nun also eine Sequence erzeugen, auf Basis von product1 und product2, und diese kann ich auch ausgeben. Im Hintergrund handelt es sich trotzdem hierbei um eine Liste. Allerdings nutze ich das Sequence-Interface, das es mit nicht erlaubt, ein Element hinzuzufügen. Ich kann also beispielsweise nicht wie im Falle einer Liste "sequence" Doppelpunkt ,Doppelpunkt "=" und dann "product3" schreiben. Wenn ich also tatsächlich eine Sequence erweitern wollen würde, müsste ich daraus eine Liste machen. Das ist auch relativ einfach möglich. Beispielsweise kann ich nun also product Nummer 3 über die doppelte Doppelpunt-Notation zu einer "sequence.toList" hinzufügen. Eine Sequence würde ich also immer dann verwenden wollen, wenn ich nicht möchte, das später noch Elemente hinzugefügt werden. Denn auch aufgrund des Immutability-Charakters dies für die Imüplementierungen innerhalb meiner Logik keine Rolle spielen sollte. Eine alternative Datenstruktur zur Liste ist der Vektor. Einen Vektor erzeuge ich mit der Notation "vector" Klammer auf, und dann kann ich beispielsweise Produkte übergeben, wie in meinem Fall product1 und product2. Ein Vektor wird arbeitsspeichertechnisch im Hintergrund etwas anders genutzt als eine Liste. Vektoren eignen sich besonders dann gut, wenn man zufällige Zugriffe innerhalb der Liste vornehmen möchte. Deswegen gibt es auf einem Vektor auch keine prepend-Funktion, wie beispielsweise auf einer Liste. Wenn ich also einen prepend durchführen möchte, beispielsweise für product3, so existiert diese Syntax nicht. Allerdings kann ich ähnlich wie auch für eine Liste einen ganz normalen append durchführen. Eine weitere Datenstruktur, die es noch gibt, ist eine sogenannte Queue. Eine Queue zeichnet sich dadurch aus, dass sie im Regelfall geleert wird mit der Zeit. Also ich kann nun beispielsweise eine Queue, oder auch Warteschlange, mit zwei Produkten initialisieren, also product1 und product2. Wenn ich nun später noch ein Element hinzufügen möchte, würde ich dieses hinten hinzufügen mithilfe der Notation ": + =", also wieder ein append, und product Nummer 3. Dann kann ich beispielsweise mal den Inhalt dieser Queue betrachten und als Nächstes könnte ich nun versuchen, aus dieser Queue ein Element heraus zu extrahieren. Beispielsweise, da es sich hierbei um eine first-in-first-out-Queue handelt, also das oberste Element. In meinem Fall also product Nummer 1. Dafür nutze ich die Funktion "dequeue". Diese gibt ein Tupel zurück. In diesem Tupel befindet sich zum einen mein Produkt, das nenne ich nun "newProduct", als auch die übrige Liste. Diese beiden Elemente gebe ich nun noch auf der Konsole aus und teste das Ganze. Ich habe also initial eine Queue von drei Elementen bei der sich die Nintendo Switch am Anfang befindet. Mit dem "dequeue" ziehe ich also die Nintendo Switch aus dieser Queue heraus und danach bleibt nur noch eine Queue mit dem Smartphone und dem IPad. Bei all diesen Datenstrukturen handelt es sich um geordnete Datenstrukturen. Alternativ dazu gibt es noch ein sogenanntes Set. Bei einem Set bekomme ich also keine Garantie dafür, ob die Reihenfolge, mit der ich Elemente in das Set hinzufüge, auch die Reihenfolge der Elemente ist, wie ich sie aus dem Set abfragen kann. Ich initialisiere also mein Set nun mit einem product1 und einem product2 dann füge ich noch ein product3 hinzu und testweise zusätzlich noch eine weitere Instanz von product1. Die Besonderheit an einem Set ist also weiterhin, dass ich ein Element nur einmal in dieser Liste haben kann. Das bedeutet auch, dass das Hinzufügen eines Elements immer damit einhergeht, dass die gesamte Liste überprüft wird, ob das Element bereits existiert. Insgesamt ist so also die reguläre Liste die effizienteste Datenstruktur, um Datenelemente zu einer Liste später noch hizufügen zu können. Weitere Informationen zu dem Thema Performance und Listen innerhalb von Scala findet man in der Dokumentation auf der Scala-Seite. Da gibt es dann für verschiedenste Operationen eine Angabe der Komplexität und der Rechenzeit, Und je nachdem kann man sich für die richtige Datenstruktur entscheiden. Die Scala-Programmiersprache definiert also innerhalb ihrer Bibliotheken eigene Datentypen für Listen, die im Gegensatz zu Java immutable sind. Das bedeutet, man kann zu einem späteren Zeitpunkt nicht mehr den Inhalt ändern, ohne eine neue Instanz dieser Liste zu erzeugen. Diese Garantien sind besonders bei der Entwicklung von parallelen Anwendungen sehr wichtig. Wenn man nun beispielsweise auf ein einzelnes Element in einer solchen Liste zugreifen würde, würde man statt einer Notation mit eckigen Klammern eine Notation mit runden Klammern verwenden. und dann würde man beispielsweise anhand des Index das Element auswählen. Eine Sequence ist nun also eine generische Liste mit Reihenfolge. Das Besondere an dieser Art von Liste ist, dass sie später so in ihrer Form nicht mehr veränderlich ist und zum Beispiel erst in eine richtige Liste konvertiert werden muss. Eine Liste ist eine einfach Liste, die Zugriff in Reihenfolge garantiert. Dadurch ist sie besonders effizient, wenn man Elemente am Anfang dieser Liste hinzufügt. Ein Vektor ist auch eine einfache Liste, allerdings ist der Zugriff hier eher per Zufall vorgesehen. Dadurch fügt man ein Element üblicherweise ans Ende eines Vektors. Ein Set hingegen ist eine Liste ohne eine definierte Reihenfolge. Des Weiteren kann jedes Element in einem solchen Set nur einmal existieren. Zu guter Letzt gibt es noch die Queue. Das ist eine Liste mit einer sogenannten FIFO-Semantik; also first-in-first-out. Ein Element das also in eine Queue hizugefügt wird, wird als allererstes wieder aus der Queue extrahiert. Scala-Listen definieren zusätzlich auch noch einige Hilfsoperationen. Gezeigt habe ich Ihnen beispielsweise die Möglichkeit, zu prüfen, ob eine Liste leer ist, mithilfe von "isEmpty". Man kann das erste Element einer Liste relativ einfach abrufen. Alternativ könnte man selbstverständlich auch den Index "0" verwenden.

Scala Grundkurs

Entdecken Sie die Möglichkeiten und Eigenschaften der modernen Programmiersprache Scala.

4 Std. 44 min (39 Videos)
Derzeit sind keine Feedbacks vorhanden...
Software:
Exklusiv für Abo-Kunden
Erscheinungsdatum:12.04.2017

Dieser Online-Kurs ist als Download und als Streaming-Video verfügbar. Die gute Nachricht: Sie müssen sich nicht entscheiden - sobald Sie das Training erwerben, erhalten Sie Zugang zu beiden Optionen!

Der Download ermöglicht Ihnen die Offline-Nutzung des Trainings und bietet die Vorteile einer benutzerfreundlichen Abspielumgebung. Wenn Sie an verschiedenen Computern arbeiten, oder nicht den ganzen Kurs auf einmal herunterladen möchten, loggen Sie sich auf dieser Seite ein, um alle Videos des Trainings als Streaming-Video anzusehen.

Wir hoffen, dass Sie viel Freude und Erfolg mit diesem Video-Training haben werden. Falls Sie irgendwelche Fragen haben, zögern Sie nicht uns zu kontaktieren!