Laden...

Wie kann ich eine List<Tuple<string, double>>() sortieren?

Erstellt von TKipp vor 5 Jahren Letzter Beitrag vor 5 Jahren 3.123 Views
T
TKipp Themenstarter:in
18 Beiträge seit 2019
vor 5 Jahren
Wie kann ich eine List<Tuple<string, double>>() sortieren?

Hallo Leute,
folgender Code


          foreach(CalculatedMissionTimeBooking booking in bookings) {
                                                    double awIstime = booking.awIsTime;
                                                    string mechanicGropuNumber = booking.mechanicGroupNumber;
                                                    string personnelNumber = String.Empty;
                                                    myList = getDataBack(booking.mechanicGroupNumber, booking.awIsTime,myList);
                                                }


     private static List<Tuple<string, double>> getDataBack(string id, double time, List<Tuple<string, double>> liste) {
            liste.Add(new Tuple<string, double>(id, time));
            return liste;
        }
 

erstellt mir eine Liste, wie im Anhang aufgezeigt(Debugging)
Meine Frage wäre nun folgende:
Wie codiere ich obigen Code weiter, um jene Values(also das zweite Element des jeweilgen Tupels) der Liste aufzuaddieren, sofern der erste des jeweiligen Tupels gleich ist. Im vorliegenden Fall sollte das dann so aussehen:

Das Ergebnis sollte als Liste wieder zurück gegeben werden. Was ich suche ist der eigentliche Algorithmus, der meine Intention umsetzt. Ideen? Die Liste ist natürlich nur ein Beispiel. Deren Inhalte können bei jedem Aufruf anderst sein.

TKipp

T
2.219 Beiträge seit 2008
vor 5 Jahren

Anstelle einer Tupel solltest du dir eine eigene Datenklasse anlegen.
Dann kannst du die Liste auch per Sort einfach sortieren.

Du missbrauchst hier Tupel als Daten Container, was schon der erste Fehler ist.
Daten sollten immer gekapselt werden, also in einer Klasse zusammengesetzt.

Ebenfalls brauchst du deine Liste nicht bei der Methode zurück zugeben.
Klassen Instanzen werden in C# immer als Referenzen übergeben.
Wenn du diese nicht änderst durch überschreiben mit new/null dann kannst du diese als normale Parameter mitgeben.


public class MyItem
{
	public string Id { get; set; }
	
	public double Time { get; set; }
}
          
List<MyItem> list = new List<MyItem>();
		  
foreach(CalculatedMissionTimeBooking booking in bookings) 
{
	double awIstime = booking.awIsTime;
    string mechanicGropuNumber = booking.mechanicGroupNumber;
    string personnelNumber = String.Empty;
    list.Add(new MyItem() { Id = booking.mechanicGroupNumber, Time = booking.awIsTime });
}

list.Sort((i1, i2) => i1.Id.CompareTo(i2.Id));

Links:
https://docs.microsoft.com/de-de/dotnet/api/system.collections.generic.list-1.sort?view=netframework-4.7.2

Falls die Liste immer sortiert sein soll, lohnt auch ein Blick auf SortedSet<T>:
https://docs.microsoft.com/de-de/dotnet/api/system.collections.generic.sortedset-1?view=netframework-4.7.2

T-Virus

Developer, Developer, Developer, Developer....

99 little bugs in the code, 99 little bugs. Take one down, patch it around, 117 little bugs in the code.

T
TKipp Themenstarter:in
18 Beiträge seit 2019
vor 5 Jahren

Danke für den Tipp, wenngleich meine Frage dadurch nicht beantwortet wurde. Dass für jedes Algorithmusproblem immer eine eigene Klasse erstellt werden soll, ist mir neu...

TKipp

16.807 Beiträge seit 2008
vor 5 Jahren

Ich stimme hier T-Virus auch nicht wirklich zu, denn das ist prinzipiell ein klassischer Fall für ein Dictionary.

D.h. ich würde das Addieren gar nicht im Nachhinein, sondern beim Erstellen lösen, sofern dies möglich ist.
Wenn es doch im Nachgang erwünscht ist würde man halt anhand des Keys gruppieren (GroupBy) und dann die Values summieren.

Sehe hier keine Notwendigkeit einer zusätzlichen Klasse.

T
TKipp Themenstarter:in
18 Beiträge seit 2019
vor 5 Jahren

Und wie implementiere ich den Algorithmus jetzt am elegantesten? Ein Dictionary ist eine eher schlechte Wahl, da das doppelte Keys erst gar nicht zulässt, oder?

TKipp

16.807 Beiträge seit 2008
vor 5 Jahren

Wenn Du ein Dictionary verwendest, dann beim Hinzufügen eben ein "Add or Update" durchführen (der Indexer bietet sich hier an).

Wenn Du es im Nachgang via Linq machen willst, dann eben mit GroupBy und einem Sum.

T
TKipp Themenstarter:in
18 Beiträge seit 2019
vor 5 Jahren

Bin fürwahr kein LINQ-Experte. wie würdest du denn das Query formulieren. In SQL würde ich das in etwa so machen:

SELECT SUM(value2),value1 FROM tbl WHERE value1=value1+1 GROUP BY value1 ;

TKipp

16.807 Beiträge seit 2008
vor 5 Jahren

Du, ich werde jetzt nicht den Code für Dich schreiben - das ist nicht mein Job 🙂
Musst schon vielleicht 20 Minuten in Linq investieren, damit Du es selbst verstehst und dann auch ein Erfolgserlebnis hast 👍

Also beschäftige Dich mal nen bisschen damit, und wenn Du es dann nicht hinbekommst, dann zeigst, was Du versuchst hast und wir schubsten Dich weiter in die richtige Richtung.

T
2.219 Beiträge seit 2008
vor 5 Jahren

@Abt
Das Problem ist nur, dass die Frage zum Zeitpunkt meiner Antwort noch nicht mal vorhanden war.
Bis auf die zwei Bilder sowie dem Titel war der Beitrag fast leer und ohne erkennbares Problem.

@TKipp
Hier solltest du, wenn du schon nicht genau weißt wie du es lösen sollst, mal einen Blick in die Doku schauen oder Google anschmeißen.
Dort gibt es für Linq genug Beispiele.

Link:
https://docs.microsoft.com/de-de/dotnet/csharp/linq/group-query-results

T-Virus

Developer, Developer, Developer, Developer....

99 little bugs in the code, 99 little bugs. Take one down, patch it around, 117 little bugs in the code.

16.807 Beiträge seit 2008
vor 5 Jahren

Dann frage ich mich, wieso Du auf eine Sache in der Form antwortest, wenn der Kontext nicht erkennbar ist 🙂
Manchmal ist auch weniger mehr 👍 (my 50c 😉)

T
2.219 Beiträge seit 2008
vor 5 Jahren

@Abt
Wenn der TE erst noch 5 mal seinen Beitrag ändert im nachinwein, wie soll man dann überhaupt sinnvoll helfen?
Vorallem wenn die Frage selbst nicht mal das vollständige Problem abdeckt und im Code auch nicht ersichtlich ist, was das eigentliche Ziel ist?
Nur so mein Einwurf dazu 😕

T-Virus

Developer, Developer, Developer, Developer....

99 little bugs in the code, 99 little bugs. Take one down, patch it around, 117 little bugs in the code.

T
TKipp Themenstarter:in
18 Beiträge seit 2019
vor 5 Jahren

Oh, der Link ist cool. LINQ ist cool, und so wie's aussieht ziemlich mächtig. Da werde ich mich dann wohl mal reinfuchsen, zumindest solange, bis ich auf das richtige Query gekommen bin. Zwei Stichwörter wurden mir ja bereits geliefert. Sum und GroupBy...:=)

TKipp

16.807 Beiträge seit 2008
vor 5 Jahren

Super Tool dafür: https://www.linqpad.net/

T
TKipp Themenstarter:in
18 Beiträge seit 2019
vor 5 Jahren

Ohh, das ist ja fast wie Weihnachten, hier :=)

Vorab mein Query:

Dictionary<string, double> dic = myList.
                      GroupBy(t => t.Item1).
                      Where(grp => grp.Count() > 1).ToDictionary(grp => grp.Key,                                                      
                       grp => grp.Select(tuple => tuple.Item2).Sum());

Das Query liefert die richtigen Werte. Die Frage ist jedoch: Funktioniert das auch, wenn die Eingangsliste mehrere Gruppen enthält, wenn also mehre Werte für das string im tuple vorliegen?

TKipp

16.807 Beiträge seit 2008
vor 5 Jahren

Wozu das Where? Wozu das ToDctionary? Das macht doch kein sinn 😉
Zweiteres tut gar nicht sooooo weh - ersteres jedoch schon.
Du brauchst nur das Group und dasSum (und den Basisbefehl Select, ohne den eh nix geht).

Das Query liefert die richtigen Werte. Die Frage ist jedoch: Funktioniert das auch, wenn die Eingangsliste mehrere Gruppen enthält, wenn also mehre Werte für das string im tuple vorliegen?

Probiers doch einfach aus 😃

T
TKipp Themenstarter:in
18 Beiträge seit 2019
vor 5 Jahren

Korrigiere mich bitte, sofern ich falsch liege:
Das where benötige ich, um nur diejenigen stringTupelWerte , die mehr als einmal vorkommen, zu gruppieren. Sonst wird doch jeder Eintrag gruppiert. Das aber will ich nicht.
Das ToDictionary() benötige ich, um sicher zu gehen, dass jedes stringTupel wirklich nur einmal vorkommt, da eine Exception ausgeworfen wird, wenn versucht wird, einen Key mehrfach in ein Dictionary einzufügen.

Ausprobieren kann ich es nicht so ohne weiteres, da die Objekte von einem Webservice abhängen. Ich könnte natürlich ein Konsolenprojekt mit einer manuell erstellten Tupelliste implementieren, denke aber, dass ein C# bzw. LINQ Profi auf einen Blick erkennen kann, ob das Query nur zufällig die richtigen Werte liefert, oder ob das immer der Fall sein wird.

Was meintest du mit "Zweiteres tut gar nicht sooooo weh - ersteres jedoch schon."?? Dass mir die Where Klausel u.U um die Ohren fliegen könnte? Wenn ja, warum?

TKipp

16.807 Beiträge seit 2008
vor 5 Jahren

Das where benötige ich, um nur diejenigen stringTupelWerte , die mehr als einmal vorkommen, zu gruppieren.

Okay, ging irgendwie nicht klar aus Deinen Beiträgen hervor.

Das ToDictionary() benötige ich, um sicher zu gehen, dass jedes stringTupel wirklich nur einmal vorkommt, da eine Exception ausgeworfen wird, wenn versucht wird, einen Key mehrfach in ein Dictionary einzufügen.

Das Gruppieren sorgt ja schon dafür, dass es von jedem Key nur eine Gruppe geben kann.

Ich könnte natürlich ein Konsolenprojekt mit einer manuell erstellten Tupelliste implementieren, denke aber, dass ein C# bzw. LINQ Profi auf einen Blick erkennen kann, ob das Query nur zufällig die richtigen Werte liefert, oder ob das immer der Fall sein wird.

Natürlich kannst Du das testen - oder willst Du etwa keine Tests für Deine Software schreiben?
[Artikel] Unit-Tests: Einführung in das Unit-Testing mit VisualStudio

T
TKipp Themenstarter:in
18 Beiträge seit 2019
vor 5 Jahren

Tja, das Grundproblem ist bekannt. Außer Black- und Whiteboxtests habe ich bisher noch keinerlei Tests betrieben. Es ist ein zusätzlicher Aufwand, Testmodule zu implementieren, unabhängig davon, dass man sich erstmal in die Thematik einarbeiten muss. Selbst für meine yii2 Projekte habe ich bisher die Testklassen des Frameworks nie benutzt. Funktioniert haben sie eigentlich dennoch. Mir leuchtet, auch nachdem ich den verlinkten Artikel gelesen habe, nicht wirklich ein, dass der zusätzliche Aufwand rentabel ist. Für Megaprojekte mag das notwendig sein, aber für kleinere(mit maximal 10 Klassen), na ja, ich weiß nicht...
Wurden für dieses Forum Tests geschrieben; eher nicht. Funktionieren tut es trotzdem 😉

TKipp

5.657 Beiträge seit 2006
vor 5 Jahren

Gut, daß du darauf hingewiesen hast. Sonst würden am Ende noch alle Entwickler ihre Zeit damit verschwenden zu testen, ob ihre Software auch das tut, was sie tun soll.

Weeks of programming can save you hours of planning

16.807 Beiträge seit 2008
vor 5 Jahren

TEs ist ein zusätzlicher Aufwand, Testmodule zu implementieren, unabhängig davon, dass man sich erstmal in die Thematik einarbeiten muss.

Nimms mir nicht übel, aber diese Aussage offenbart, dass Du es nicht im Ansatz verstanden hast 🙂
Wenn Testen Dich Aufwand kostet und Code deswegen umgeschrieben wurde/werden müsste, dann war/ist Dein Code einfach halt auch scheisse - so deutlich kann man es sagen 🙂

Aber hört sich jetzt - mit den aktuellen Themen - auch ingesamt an, dass Du Software eher als Hobby statt als professionellen Weg betrachtest.
Daher tust Du hier extrem viel Leuten unrecht. Ob Du mit dieser Aussage bei professionellen Unternehmen weit kommen würdest.... bezweifle es 😉

Selbst für meine yii2 Projekte habe ich bisher die Testklassen des Frameworks nie benutzt.

Hint: das ist kein Problem des Frameworks, auch wenn es PHP ist.
Eher mal an die eigene Nase fassen.

Mir leuchtet, auch nachdem ich den verlinkten Artikel gelesen habe, nicht wirklich ein, dass der zusätzliche Aufwand rentabel ist.

Siehe Quote #1

Wurden für dieses Forum Tests geschrieben; eher nicht.

Ja, wurden. Sowohl für PHP wie auch .NET Parts.

T
2.219 Beiträge seit 2008
vor 5 Jahren

Selbst bei einem Projekt mit 10 Klassen kann es schon Prozesse geben, die einen gewissen Grad an Komplexität erreichen, wo Tests nicht nur sinnvoll sondern auch notwendig sind.
Die Größe des Projekts und die Anzahl der Klassen sagt nicht viel über den Sinn von Unit Tests aus.
Unit Tests sind im Bereich von Test Driven Development sogar ein Fundament ohne das man gar nicht sinnvoll arbeiten kann.
Dort werden die Tests meistens vor bzw. während der eigentlichen Prozess Implementierung umgesetzt um das gewünschte Ergebnis direkt bei der Umsetzung abzusichern.

Auch bei kleinen Projekten, bei denen sich selbst kleine Prozesse mit der Zeit aufblähen muss immer gewährleistet sein, dass bei Anpassungen die Prozesse noch gültige Ergebnisse liefern.
Und genau dies sichert man damit ab.

T-Virus

Developer, Developer, Developer, Developer....

99 little bugs in the code, 99 little bugs. Take one down, patch it around, 117 little bugs in the code.

T
TKipp Themenstarter:in
18 Beiträge seit 2019
vor 5 Jahren

"Wenn Testen Dich Aufwand kostet und Code deswegen umgeschrieben wurde/werden müsste, dann war/ist Dein Code einfach halt auch scheisse - so deutlich kann man es sagen 😃"

Wie meinst du dass?
Weswegen muss man Code umschreiben, um ihn zu testen?
Was ich meinte ist, dass zusätzlicher Code geschrieben werden muss, der nix anderes macht, um den eigentlichen Code zu testen. Das ist doch zusätzlicher Aufwand, der dadurch betrieben wird...

"Die große Frage ist häufig: „Wozu brauchen wir denn Unit Tests, unsere Applikation läuft doch einwandfrei?“ Doch selbst wenn ein Programm fehlerfrei zu laufen scheint, können sich Fehler eingeschlichen haben, die auf den ersten Blick nicht ersichtlich sind. Teilweise funktionieren bestimmte Programmteile monatelang problemlos und erst durch umfangreiches Unit Testing, das alle Eventualitäten abdeckt, werden Fehler im Quellcode aufgedeckt...."

Ich stimme dem vorbehaltlos zu, aber die Entwicklung von Code, der oben genannte Test durchführt, schreibt sich doch nicht von selbst?!
Oder gibt es Möglichkeiten, derartige Testmodule automatisiert erstellen zu lassen?

TKipp

T
2.219 Beiträge seit 2008
vor 5 Jahren

Nein, dass ist die Aufgabe des Entwicklers der den Code schreibt.
Oder eben bei bestehendem Code von dem jenigen der den entsprechenden Code anpassen will.

Wie soll ein automatisiertes System auch wissen welche Funktionen du testen willst und welche Ergebnisse du mit bestimmten Parametern beabsichtigst?
Unit Tests muss man immer, unabhängig von der Programmiersprache, Platform o.ä. selbst schreiben.

Klar ist das zusätzlicher Aufwand, aber dieser stellt eben fir Funktionen bei Änderungen deines Codes sicher.
Den wenn was kaputt geht oder deine Funktionen falsche Werte liefern, dann willst du nicht erst aufwändig manuell alle Testfälle durch spielen wollen.
Dafür hat man schließlich die Unit Tests die dann die Gesamtintigrität deines Code bei ausreichender Unit Test Abdeckung sicherstellt.

T-Virus

Developer, Developer, Developer, Developer....

99 little bugs in the code, 99 little bugs. Take one down, patch it around, 117 little bugs in the code.

T
TKipp Themenstarter:in
18 Beiträge seit 2019
vor 5 Jahren

Okay. Danke für Eure Statements. Will mich dem Schreiben von Tests eigentlich auch nicht prinzipiell verweigern. In diesem Sinne habe ich gestern mein erstes Testmodul geschrieben, oder besser, via Copy und Paste integriert - zum Lernen, halt (siehe hier.

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title></title>
    </head>
    <body>
        <p><a href="https://phpunit.de/getting-started/phpunit-7.html">Source</a></p>
    <center>
        <h2>Test Driven Development</h2>
        <h3>Call test </h3>
    </center>
    <p><ul><li>X:</li></ul>
    <ul><li>cd X:\xampp\htdocs\TestDrivenDevelopment</li></ul>
    <ul><li>cd vendor/bin</li></ul>
    <ul><li>phpunit --bootstrap X:\xampp\htdocs\TestDrivenDevelopment\vendor\autoload.php X:\xampp\htdocs\TestDrivenDevelopment\tests\EmailTest</li></ul>
</body>
</html>

Sind derartige Tests prinzipiell nur mit der Konsole anzustoßen? Sicher gibt es derartige Testmodule auch für C#? Läuft das dann gleich ab, oder ist das bereits in VisualStudio integriert?

TKipp

4.931 Beiträge seit 2008
vor 5 Jahren

In C# ist das, wie im Unit-Test Artikel beschrieben, schon im Visual Studio integriert.

Am einfachsten beginnst du, indem du bei einer öffentlichen Methode den Kontextmenü-Eintrag "Create Unit Tests" aufrufst (die Einstellungen im Dialog kannst du so lassen und dann mit "OK" bestätigen).

Und über den "Test-Explorer" kannst du dann die Tests starten (alle oder individuell - und sogar debuggen 😉.

16.807 Beiträge seit 2008
vor 5 Jahren

Was ich meinte ist, dass zusätzlicher Code geschrieben werden muss, der nix anderes macht, um den eigentlichen Code zu testen. Das ist doch zusätzlicher Aufwand, der dadurch betrieben wird...

Du hast noch nie in einem profesionellen Software-Umfeld gearbeitet, oder? 🤔 Aber nicht schlimm. Nur passen halt solche Äußerungen einfach nicht.
Tests - gerade Unit Tests - relativieren sich oft binnen weniger Tage. Manchmal sogar in Stunden.

Tests sparen Zeit und Geld. Massiv.
Es gibt keinen anderen Weg als durch Tests die Funktionsweise einer Software nachzuweisen.
Solltest Du was anderes haben, dann könntest Du mit dieser Idee extrem viel Geld verdienen.
Nur mit "Hey, vertrau mir. Die Software wird schon funktionieren" kommst halt ned weit.

Sind derartige Tests prinzipiell nur mit der Konsole anzustoßen?

Du hast hier offensichtlich ein Integrationstest und kein Unit Test.
Ein Integrationstest ist "teuer", weil er viel mehr Aufwand und Ressourcen benötigt.

Daher versucht man so viel mit Unit Tests abzudecken, weil diese die absolut günstigste Art und Weise ist, wie man Software Testen kann.
Les Dir einfach den Beitrag durch, der Dir verlinkt wurde.