using System; using System.Collections.Generic; using System.Linq; using Project_Periodensystem.Model; namespace Project_Periodensystem.Controller { /// /// ElementStatistics - Spezialisierte Klasse für statistische Berechnungen und Datenanalyse /// /// Diese Klasse wurde aus dem Haupt-Controller ausgelagert, um das Single Responsibility /// Principle zu befolgen. Sie konzentriert sich ausschließlich auf: /// /// - Mathematische Berechnungen (Durchschnitte, Extreme) /// - Datengruppierung und -analyse (Serien, Kategorien) /// - Informationsextraktion (Tuple-basierte Abfragen) /// - Performance-optimierte LINQ-Operationen /// /// Vorteile der Auslagerung: /// - Bessere Testbarkeit einzelner Berechnungen /// - Wiederverwendbarkeit der Statistik-Funktionen /// - Klare Trennung von UI-Logik und Datenverarbeitung /// - Einfache Erweiterung um neue Statistiken /// public class ElementStatistics { /// /// Private, schreibgeschützte Liste aller Elemente für statistische Berechnungen. /// Wird im Konstruktor gesetzt und bleibt danach unveränderlich (readonly). /// Garantiert Datenintegrität während der gesamten Lebensdauer des Objekts. /// private readonly List _elements; /// /// Konstruktor der ElementStatistics-Klasse. /// Initialisiert die Statistik-Engine mit einer Element-Sammlung. /// /// Design-Prinzipien: /// - Dependency Injection: Element-Liste wird von außen bereitgestellt /// - Defensive Programmierung: Null-Safety durch Fallback /// - Unveränderlichkeit: readonly field für Datensicherheit /// /// Liste der Elemente für statistische Auswertungen (kann null sein) public ElementStatistics(List elements) { // Null-Safety: Falls null übergeben wird, erstelle eine leere Liste // Verhindert NullReferenceExceptions in allen nachfolgenden Methoden _elements = elements ?? new List(); } /// /// Extrahiert alle Atomgewichte als Array - demonstriert klassische Array-Erstellung /// /// C# KONZEPTE: /// - Array-Initialisierung: new double[size] /// - For-Schleife: Imperative Programmierung /// - Property-Zugriff: element.AtomicWeight /// /// ALTERNATIVE (LINQ): return _elements.Select(e => e.AtomicWeight).ToArray(); /// Zeigt Unterschied zwischen imperativem und funktionalem Stil /// /// Array aller Atomgewichte in g/mol public double[] GetAtomicWeights() { double[] weights = new double[_elements.Count]; for (int i = 0; i < _elements.Count; i++) { weights[i] = _elements[i].AtomicWeight; } return weights; } /// /// Berechnet das durchschnittliche Atomgewicht aller Elemente /// /// C# KONZEPTE: /// - Early Return Pattern: if (!_elements.Any()) return 0.0; /// - Method Reuse: Nutzt GetAtomicWeights() /// - Klassische Iteration: for-Schleife für Summe /// /// MATHEMATIK: Arithmetisches Mittel = Summe / Anzahl /// /// Durchschnittliches Atomgewicht oder 0.0 bei leerer Liste public double GetAverageAtomicWeight() { if (!_elements.Any()) return 0.0; double[] weights = GetAtomicWeights(); double sum = 0; for (int i = 0; i < weights.Length; i++) { sum += weights[i]; } return sum / weights.Length; } /// /// Sammelt alle einzigartigen Element-Serien - demonstriert LINQ-Pipeline /// /// C# KONZEPTE: /// - LINQ Select(): Projektion (e => e.Series) /// - LINQ Distinct(): Entfernt Duplikate /// - LINQ Where(): Filtert leere/null Werte /// - LINQ OrderBy(): Alphabetische Sortierung /// - Method Chaining: Verkettung mehrerer Operationen /// /// RÜCKGABE: Sortierte Liste aller chemischen Serien /// /// Liste aller Element-Serien (Alkalimetall, Edelgas, etc.) public List GetAllSeries() { return _elements.Select(e => e.Series) // Projektion .Distinct() // Duplikate entfernen .Where(s => !string.IsNullOrWhiteSpace(s)) // Null/Empty filtern .OrderBy(s => s) // Alphabetisch sortieren .ToList(); // Zu Liste konvertieren } /// /// Sammelt wichtige Statistiken in einem Tuple - demonstriert strukturierte Rückgaben /// /// C# KONZEPTE: /// - Tuple Return Type: (int, int, double) /// - Method Delegation: Ruft andere Methoden auf /// - Tuple Creation: (value1, value2, value3) /// /// VERWENDUNG: var (total, series, avg) = statistics.GetStatistics(); /// /// Tuple mit (Anzahl Elemente, Anzahl Serien, Durchschnittsgewicht) public (int totalElements, int uniqueSeries, double avgWeight) GetStatistics() { var seriesCount = GetAllSeries().Count; var avgWeight = GetAverageAtomicWeight(); return (_elements.Count, seriesCount, avgWeight); } /// /// Findet das leichteste und schwerste Element - demonstriert LINQ Ordering /// /// C# KONZEPTE: /// - LINQ OrderBy() / OrderByDescending(): Sortierung /// - LINQ First(): Erstes Element nach Sortierung /// - Tuple mit nullable Types: (Element?, Element?) /// - Guard Clause: Early return bei leerer Liste /// /// CHEMIE: Wasserstoff ist leichtestes (1.008), schwerste variieren /// /// Tuple mit (leichtestes Element, schwerstes Element) oder (null, null) public (Element? lightest, Element? heaviest) GetWeightExtremes() { if (!_elements.Any()) return (null, null); var lightest = _elements.OrderBy(e => e.AtomicWeight).First(); var heaviest = _elements.OrderByDescending(e => e.AtomicWeight).First(); return (lightest, heaviest); } /// /// Extrahiert Element-Informationen nach Ordnungszahl - demonstriert Tuple-basierte APIs /// /// C# KONZEPTE: /// - LINQ FirstOrDefault(): Sichere Suche (kann null zurückgeben) /// - Conditional Operator: condition ? trueValue : falseValue /// - Tuple mit Mixed Types: (string, string, double) /// /// FALLBACK: Bei nicht gefundenem Element ("?", "Unknown", 0.0) /// /// Ordnungszahl des gesuchten Elements (1-118) /// Tuple mit (Symbol, Name, Atomgewicht) public (string symbol, string name, double weight) GetElementInfo(int atomicNumber) { var element = _elements.FirstOrDefault(e => e.AtomicNumber == atomicNumber); return element != null ? (element.Symbol, element.ElementName, element.AtomicWeight) : ("?", "Unknown", 0.0); } /// /// Ermittelt die Position eines Elements im Periodensystem-Grid /// /// C# KONZEPTE: /// - Konsistente API: Gleiche Suchmuster wie GetElementInfo() /// - Tuple für Koordinaten: (int row, int column) /// - Fallback-Werte: (-1, -1) für "nicht gefunden" /// /// VERWENDUNG: var (row, col) = statistics.GetElementPosition(1); // Wasserstoff /// /// Ordnungszahl des gesuchten Elements /// Tuple mit (Zeile, Spalte) oder (-1, -1) wenn nicht gefunden public (int row, int column) GetElementPosition(int atomicNumber) { var element = _elements.FirstOrDefault(e => e.AtomicNumber == atomicNumber); return element != null ? (element.Row, element.Column) : (-1, -1); } } }