Entwickler-Ecke
Basistechnologien - Wörter in Console umkehren
Csharp-programmierer - Fr 27.11.15 14:59
Titel: Wörter in Console umkehren
Hallo. Ich bun gerade dabei eine Consolenanwendung zu schreiben, welche die eingegebenen Wörter in eine andere Reihenfolge sortiert. Gehe ich ein:
Heuten ist schönes Wetter, dann soll rauskommen: Wetter schönes ist heute.
Wie kann ich dir Wörter auch bei anderen Texten so umdrehen wie in Beispiel?
Mfg
Moderiert von
Th69: Topic aus Algorithmen, Optimierung und Assembler verschoben am Fr 27.11.2015 um 14:44
Palladin007 - Fr 27.11.15 15:07
Splitte am Leerzeichen, kehre das daraus folgende Array um und verkette die Items wieder als String.
C#-Quelltext
1: 2: 3:
| string.Split IEnumerable.Reverse string.Concat |
Moderiert von
Th69: C#-Tags hinzugefügt
Csharp-programmierer - Fr 27.11.15 15:23
Vielen Dank. Ich hätte mal wieder alles komplizierter gemacht.
Doch wenn ich nun die Umgekehrte Reihenfolge der Wörter ausgeben lasse, schließt sich die Console wieder. Wie kann ich das vermeiden?
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25:
| try { string s = Console.ReadLine(); string[] ss = s.Split(' ');
string[] x = ss.Reverse().ToArray(); foreach (string sdf in x) { y += String.Concat(sdf) + " "; } Console.WriteLine(y); y = null; ss = null; s = null; x = null; Console.ReadKey(); } catch (ArgumentException) { Console.WriteLine("Please writer Text in the console."); } catch (Exception ex) { Console.WriteLine(ex.Message);a } |
Ralf Jansen - Fr 27.11.15 15:44
Den foreach kannst du durch string.Join oder Aggregate() ersetzen.
Warum dein Console.ReadKey() nicht zieht und sich deine Console schließt weiß ich nicht, sollte er eigentlich auch nicht.
C#-Quelltext
1: 2: 3: 4: 5: 6:
| public static void Main(string[] args) { string y = Console.ReadLine().Split(' ').Reverse().Aggregate((f, s) => f + " " + s); Console.WriteLine(y); Console.ReadKey(); } |
Palladin007 - Fr 27.11.15 18:20
Weil eine Exception auftritt, in den Catch-Blöcken gibt es kein Console.ReadKey
@Ralf:
Die Nutzung von Aggregate ist in diesem Fall ziemlich unpraktisch und auch langsam.
Die effektivste Variante ist string.Concat, der Performance-Unterschied ist ziemlich groß, genaue Zahlen hab ich aber nicht im Kopf.
Ralf Jansen - Sa 28.11.15 14:02
Zitat: |
@Ralf:
Die Nutzung von Aggregate ist in diesem Fall ziemlich unpraktisch und auch langsam.
Die effektivste Variante ist string.Concat, der Performance-Unterschied ist ziemlich groß, genaue Zahlen hab ich aber nicht im Kopf. |
Wie wollen hier nur einen Satz umkehren keinen Roman :roll:
Performancebetrachtungen denke ich sind eigentlich eher irrelevant wenn würde ich auch vermuten das Aggregate kein Problem ist eher das was der Lambda Audruck macht.
Persönlich halte ich Aggregate für sehr praktisch da man es hier dann fluent aufrufen kann. Lesbarkeit wäre vielleicht ein Thema :wink:
Palladin007 - Sa 28.11.15 14:38
Aggregate hat das Problem, dass hier nicht optimiert werden kann, außerdem ist das Verketten zwei Strings über den +-Operator grundsätzlich langsam.
Aber Du hast recht, der Unterschied ist zu vernachlässigen, ich hab's nach gemessen:
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24:
| var word = "Ein schöner Satz mit vielen tollen Wörtern der jetzt umgekehrt werden soll";
var watcher = new Stopwatch();
watcher.Start(); string x = null; for (int i = 0; i < 1000000; i++) x = word.Split(' ').Reverse().Aggregate((f, s) => f + " " + s); watcher.Stop(); Console.WriteLine(x); Console.WriteLine(watcher.ElapsedMilliseconds); watcher.Reset();
Console.WriteLine(); watcher.Start(); string y = null; for (int i = 0; i < 1000000; i++) y = string.Join(" ", word.Split(' ').Reverse()); watcher.Stop(); Console.WriteLine(y); Console.WriteLine(watcher.ElapsedMilliseconds); watcher.Reset();
Console.ReadKey(); |
Das Ergebnis:
2201
1430
Bei einer Million Durchläufe ist das absolut unwichtig :D
Dennoch würde ich das im Hinterkopf behalten, einfach damit es bekannt ist, ich hab das schön als Performance-Problem enttarnen müssen ^^
Außerdem finde ich meine Variante besser :D (Außerdem habe ich mich vertan, es muss Join, nicht Concat sein, ich habe es in meinem ersten Post angepasst)
Wenn es sich später mal um deutlich längere Strings dreht, dann wird das auf einmal von Bedeutung.
Wenn ich den String auf das 100fache verlängere (100fach verkettet, Leerzeichen getrennt) und die Anzahl Durchläufe auf 10k reduziere, bekomme ich folgendes Ergebnis:
18423
1240
Das ist wiederum sehr wohl zu beachten :D
Csharp-programmierer - Sa 28.11.15 21:59
Vielen Dank Leute. Das Problem ist gelöst :)
Ralf Jansen - So 29.11.15 00:00
Ok, Performance Battle!! Nimm das :twisted:
C#-Quelltext
1: 2: 3: 4: 5: 6:
| var word = "Ein schöner Satz mit vielen tollen Wörtern der jetzt umgekehrt werden soll"; var sb = new StringBuilder(word.Length); var words = word.Split(); for (int w = words.Length - 1; w >= 0; w--) sb.Append(words[w]).Append(" "); Console.WriteLine(sb.ToString()); |
Palladin007 - So 29.11.15 00:21
Du weißt schhon, wass string.Join im Prinzip einen StringBuilder nutzt, den aber noch optimiert?
Du machst also genau das Gleiche, wie string.Join, nur langsamer, umfangreicher und sogar mit einem kleinen Bug: Am Ende wird ein falsches Leerzeichen angehängt ;)
Glaub mir, String.Join lässt sich nicht übertrumpfen :D
Außer Du willst eine Speicher-Optimierte Version haben, die berechnet dann die Ergebnis-Länge voraus und reserviert von anfang an den Platz. Das fordert weniger den Ram, ist aber allgemein auch minimal langsamer.
Ralf Jansen - So 29.11.15 00:51
Dir ist entgangen das ich den Reverse Step eingespart habe und den StringBuilder schon mit der richtigen Länge initialisiere weil ich die Ziellänge ja kenne das tut string.Join nicht (auch wenn der Rest von string.Join sicher besser ist als mein Code ich wollte aber noch halbwegs kompakt bleiben). Wenn du möchtest tu so als hätte ich die Implementierung von join geklaut die Schleife einfach anders herum laufen lassen und denn StringBuilder initialisiert. Das muss schneller sein ;)
Edit: Nicht viel schneller aber immerhin ;)
Palladin007 - So 29.11.15 03:09
Naja, bei 1 Million Durchläufe...
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27:
| var word = "Ein schöner Satz mit vielen tollen Wörtern der jetzt umgekehrt werden soll"; var watcher = new Stopwatch();
watcher.Start(); string x = null; for (int i = 0; i < 1000000; i++) { var sb1 = new StringBuilder(word.Length); var words = word.Split(); for (int w = words.Length - 1; w >= 0; w--) sb1.Append(words[w]).Append(" "); x = sb1.ToString(); } watcher.Stop(); Console.WriteLine(watcher.ElapsedMilliseconds); watcher.Reset();
Console.WriteLine(); watcher.Start(); string y = null; for (int i = 0; i < 1000000; i++) y = string.Join(" ", word.Split(' ').Reverse()); watcher.Stop(); Console.WriteLine(watcher.ElapsedMilliseconds); watcher.Reset();
Console.ReadKey(); |
Ergebnis:
1862
1547
Soviel zum Schneller :D
Wirklich schneller ist deine Variante nur, wenn der StringBuilder vor den million Durchläufen angelegt und nach dem Durchlauf geleert wird.
Allerdings können wir ja nicht davon ausgehen, dass der Satz gleich bleibt.
Abgesehen davon, wenn ich von deiner Variante ausgehe, lässt die sich doch noch optimieren:
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23:
| var word = "Ein schöner Satz mit vielen tollen Wörtern der jetzt umgekehrt werden soll"; var watcher = new Stopwatch();
watcher.Start(); string x = null; for (int i = 0; i < 1000000; i++) { var sb1 = new StringBuilder(word.Length); var words = word.Split(); var isFirst = true; for (int w = words.Length - 1; w >= 0; w--) { if (isFirst) isFirst = false; else sb1.Append(" ");
sb1.Append(words[w]); } x = sb1.ToString(); } watcher.Stop(); Console.WriteLine(watcher.ElapsedMilliseconds); |
Ergebnis:
1834
Im Prinzip ist das der Bug, dass ein Leerzeichen zu viel angehängt wird.
Das ist nur ein Leerzeichen, aber ich vermute, wenn der StringBuilder auf die Satz.Länge fest gelegt ist, muss er neu erweitern, weil das Leerzeichen zu viel sonst den String zu groß werden lassen würde.
Das kostet bei meiner Messung 28ms
Außerdem behebt diese kleine Anpassung ein Fehl-Verhalten :P
Wenn ich das ganze weiter dichte:
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21:
| var word = "Ein schöner Satz mit vielen tollen Wörtern der jetzt umgekehrt werden soll"; var watcher = new Stopwatch();
watcher.Start(); string x = null; for (int i = 0; i < 1000000; i++) { var sb1 = new StringBuilder(word.Length); var words = word.Split(); for (int w = words.Length - 1; w >= 0; w--) { if(w != words.Length - 1) sb1.Append(" ");
sb1.Append(words[w]); } x = sb1.ToString(); } watcher.Stop(); Console.WriteLine(watcher.ElapsedMilliseconds); watcher.Reset(); |
Ergebnis:
1788
74ms schneller als deine Variante und immer noch 241ms langsamer als mein vorheriger Weg mit string.Join :D
Ralf Jansen - So 29.11.15 12:35
Zitat: |
Soviel zum Schneller :D |
Deine hier gepostete Version ist bei mir (erwartungskonform) schneller als string.join ;)
Wenn man sich den if in der Schleife spart holt man noch ein paar ms raus.
C#-Quelltext
1: 2: 3:
| for (int w = words.Length - 1; w > 0; w--) sb.Append(words[w]).Append(" "); sb.Append(words[0]); |
So ca. 1060ms zu 1030ms. If sparen bringt nochmal unglaubliche 10 ms.
Th69 - So 29.11.15 12:58
Ein word besteht bei euch aus words? :o
Palladin007 - So 29.11.15 18:51
Ich glaube, ich muss mich geschlagen geben :D
Weiter optimieren geht wohl wirklich nur, wenn man sich weiter mit der Architektur auseinander setzt
Ralf Jansen - So 29.11.15 19:07
oder unsafe code benutzt wie string.join :wink:
Palladin007 - So 29.11.15 21:05
Das mein ich damit, aber das fordert detailierteres Wissen darüber, wie Strings bearbeitet werden und das fehlt mir :D
Wobei string.Join keinen unsafe Code nutzt, soweit ich das sehe, besteht der einzige Unterschied in einem StringBuilderCache
Ralf Jansen - So 29.11.15 21:35
Kommt auf die Überladung an die man benutzt. Was sich Microsoft auch immer dabei gedacht hat für string[] eine andere Implementierung als für IEnumerable<string> zu verwenden.
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2025 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!