Tutorial 3~18 MinutenAnfänger

Collections

Lerne, wie du mit Listen, Maps und Sets in Velisch arbeitest – inklusive mächtiger funktionaler Methoden wie map, filter und reduce.

Was du lernen wirst

  • Listen erstellen und manipulieren
  • Maps für Schlüssel-Wert-Paare nutzen
  • Funktionale Methoden (map, filter, reduce) anwenden
  • Collections mit Datenbank-Operationen verbinden
1

Listen (Arrays)

Listen sind geordnete Sammlungen von Elementen desselben Typs. Sie wachsen dynamisch und bieten schnellen Index-Zugriff.

Listen erstellen

// Direkte Initialisierung
let fruits = ["Apfel", "Banane", "Kirsche"];

// Mit explizitem Typ
let numbers: List<number> = [1, 2, 3, 4, 5];

// Leere Liste
let empty: List<string> = [];

// Liste mit einem Element
let single = ["Einziges Element"];

Grundlegende Operationen

let fruits = ["Apfel", "Banane"];

// Elemente hinzufügen
fruits.push("Kirsche");        // Am Ende: ["Apfel", "Banane", "Kirsche"]
fruits.insert(0, "Ananas");    // An Position 0: ["Ananas", "Apfel", ...]

// Elemente abrufen
let first = fruits[0];         // → "Ananas"
let last = fruits.last();      // → "Kirsche"
let length = fruits.length();  // → 4

// Elemente entfernen
let removed = fruits.pop();    // Entfernt letztes Element
fruits.remove(1);              // Entfernt an Index 1

// Prüfungen
let hasApple = fruits.contains("Apfel");  // → true
let isEmpty = fruits.isEmpty();            // → false

Über Listen iterieren

let users = ["Anna", "Max", "Lisa"];

// Einfache Iteration
for (user in users) {
    print("Hallo, {user}!");
}

// Mit Index
for (index, user in users) {
    print("{index + 1}. {user}");
}
// Ausgabe:
// 1. Anna
// 2. Max
// 3. Lisa

// Rückwärts iterieren
for (user in users.reversed()) {
    print(user);
}
2

Maps (Dictionaries)

Maps speichern Schlüssel-Wert-Paare und ermöglichen blitzschnellen Zugriff über den Schlüssel. Perfekt für Caches, Konfigurationen und gruppierte Daten.

Maps erstellen und verwenden

// Map erstellen
let scores = Map<string, number>.new();

// Werte setzen
scores.set("Anna", 95);
scores.set("Max", 88);
scores.set("Lisa", 92);

// Werte abrufen
let annaScore = scores.get("Anna");  // → 95

// Sicherer Zugriff mit getOrDefault
let unknownScore = scores.getOrDefault("Bob", 0);  // → 0

// Prüfungen
if (scores.has("Anna")) {
    print("Anna hat {scores.get("Anna")} Punkte");
}

// Entfernen
scores.remove("Max");

// Größe
let count = scores.size();  // → 2

Über Maps iterieren

let config = Map<string, string>.new();
config.set("host", "localhost");
config.set("port", "8080");
config.set("env", "development");

// Über Schlüssel-Wert-Paare iterieren
for (key, value in config) {
    print("{key} = {value}");
}

// Nur Schlüssel
for (key in config.keys()) {
    print(key);
}

// Nur Werte
for (value in config.values()) {
    print(value);
}

📦 Praxisbeispiel: User-Cache

let userCache = Map<string, User>.new();

fn getUser(id: string): User {
    // Erst im Cache suchen
    if (userCache.has(id)) {
        return userCache.get(id);
    }
    
    // Aus Datenbank laden
    let user = db.find(User, id);
    
    // Im Cache speichern
    userCache.set(id, user);
    
    return user;
}
3

Funktionale Methoden

Velisch bietet mächtige funktionale Methoden, um Collections elegant zu transformieren. Diese Methoden können verkettet werden für ausdrucksstarken, lesbaren Code.

map – Elemente transformieren

Wendet eine Funktion auf jedes Element an und gibt eine neue Liste zurück:

let numbers = [1, 2, 3, 4, 5];

// Verdoppeln
let doubled = numbers.map(n => n * 2);
// → [2, 4, 6, 8, 10]

// In Strings umwandeln
let strings = numbers.map(n => "Nummer: {n}");
// → ["Nummer: 1", "Nummer: 2", ...]

// Komplexere Transformation
struct User { id: string, name: string, email: string }

let users = db.findAll(User);
let names = users.map(user => user.name);
// → ["Anna", "Max", "Lisa"]

filter – Elemente filtern

Behält nur Elemente, die eine Bedingung erfüllen:

let numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

// Gerade Zahlen
let evens = numbers.filter(n => n % 2 == 0);
// → [2, 4, 6, 8, 10]

// Größer als 5
let big = numbers.filter(n => n > 5);
// → [6, 7, 8, 9, 10]

// Aktive Benutzer
let activeUsers = users.filter(user => user.isActive);

// Mit komplexer Bedingung
let admins = users.filter(user => {
    return user.role == "admin" && user.isActive;
});

reduce – Zu einem Wert aggregieren

Reduziert eine Liste auf einen einzelnen Wert:

let numbers = [1, 2, 3, 4, 5];

// Summe berechnen
let sum = numbers.reduce((acc, n) => acc + n, 0);
// → 15

// Maximum finden
let max = numbers.reduce((acc, n) => if (n > acc) n else acc, numbers[0]);
// → 5

// Objekt zusammenbauen
struct CartItem { name: string, price: number }

let cart = [
    CartItem { name: "Buch", price: 19.99 },
    CartItem { name: "Kaffee", price: 4.50 },
];

let total = cart.reduce((sum, item) => sum + item.price, 0.0);
// → 24.49

Methoden verketten

Die wahre Macht zeigt sich beim Verketten mehrerer Operationen:

struct Order {
    id: string,
    userId: string,
    total: number,
    status: string,
}

let orders = db.findAll(Order);

// Komplexe Pipeline: Abgeschlossene Bestellungen eines Users summieren
let userTotal = orders
    .filter(o => o.userId == "user_123")     // Nur User's Bestellungen
    .filter(o => o.status == "completed")    // Nur abgeschlossene
    .map(o => o.total)                       // Nur Beträge extrahieren
    .reduce((sum, t) => sum + t, 0.0);       // Summieren

// Top 3 Namen alphabetisch sortiert
let topNames = users
    .filter(u => u.score > 90)
    .map(u => u.name)
    .sorted()
    .take(3);
find()

Erstes passendes Element

users.find(u => u.id == "1")
any()

Mindestens einer erfüllt

users.any(u => u.isAdmin)
all()

Alle erfüllen Bedingung

users.all(u => u.verified)
4

Collections & Datenbank

In der Praxis arbeiten Collections oft mit Datenbank-Ergebnissen zusammen. Velisch integriert SeaORM nahtlos für typsichere Queries.

struct User {
    id: string,
    name: string,
    email: string,
    role: string,
    createdAt: string,
}

// CRUD mit Collections

// Alle User abrufen
@GET("/api/users")
fn getUsers(): List<User> {
    return db.findAll(User);
}

// User mit Filter
@GET("/api/users/admins")
fn getAdmins(): List<User> {
    return db.query(User)
        .where("role", "=", "admin")
        .findAll();
}

// User erstellen
@POST("/api/users")
fn createUser(name: string, email: string): User {
    let user = User {
        id: generateId(),
        name: name,
        email: email,
        role: "user",
        createdAt: now(),
    };
    return db.save(user);
}

// Mehrere User auf einmal erstellen (Batch)
@POST("/api/users/batch")
fn createUsers(users: List<CreateUserInput>): List<User> {
    let created = users.map(input => {
        return User {
            id: generateId(),
            name: input.name,
            email: input.email,
            role: "user",
            createdAt: now(),
        };
    });
    
    return db.saveAll(created);
}

Zusammenfassung

Was du gelernt hast:

  • Listen erstellen, manipulieren und iterieren
  • Maps für schnellen Key-Value-Zugriff
  • map(), filter(), reduce() verketten
  • Collections mit SeaORM DB-Queries

Nächste Schritte:

  • Closures für komplexere Transformationen
  • Pattern Matching für elegante Datenverarbeitung