Autor Beitrag
Csharp-programmierer
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 696
Erhaltene Danke: 10

Windows 8.1
C# (VS 2013)
BeitragVerfasst: Fr 27.11.15 14:59 
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 user profile iconTh69: Topic aus Algorithmen, Optimierung und Assembler verschoben am Fr 27.11.2015 um 14:44
Palladin007
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1282
Erhaltene Danke: 182

Windows 11 x64 Pro
C# (Visual Studio Preview)
BeitragVerfasst: Fr 27.11.15 15:07 
Splitte am Leerzeichen, kehre das daraus folgende Array um und verkette die Items wieder als String.
ausblenden C#-Quelltext
1:
2:
3:
string.Split
IEnumerable.Reverse
string.Concat


Moderiert von user profile iconTh69: C#-Tags hinzugefügt

Für diesen Beitrag haben gedankt: Csharp-programmierer
Csharp-programmierer Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 696
Erhaltene Danke: 10

Windows 8.1
C# (VS 2013)
BeitragVerfasst: 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?

ausblenden 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4700
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: 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.

ausblenden 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();
}

Für diesen Beitrag haben gedankt: Csharp-programmierer
Palladin007
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1282
Erhaltene Danke: 182

Windows 11 x64 Pro
C# (Visual Studio Preview)
BeitragVerfasst: 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4700
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1282
Erhaltene Danke: 182

Windows 11 x64 Pro
C# (Visual Studio Preview)
BeitragVerfasst: 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:

ausblenden 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 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 696
Erhaltene Danke: 10

Windows 8.1
C# (VS 2013)
BeitragVerfasst: Sa 28.11.15 21:59 
Vielen Dank Leute. Das Problem ist gelöst :)
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4700
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: So 29.11.15 00:00 
Ok, Performance Battle!! Nimm das :twisted:

ausblenden 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1282
Erhaltene Danke: 182

Windows 11 x64 Pro
C# (Visual Studio Preview)
BeitragVerfasst: 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4700
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1282
Erhaltene Danke: 182

Windows 11 x64 Pro
C# (Visual Studio Preview)
BeitragVerfasst: So 29.11.15 03:09 
Naja, bei 1 Million Durchläufe...


ausblenden 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:

ausblenden 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:

ausblenden 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4700
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: 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.

ausblenden 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4764
Erhaltene Danke: 1052

Win10
C#, C++ (VS 2017/19/22)
BeitragVerfasst: So 29.11.15 12:58 
Ein word besteht bei euch aus words? :o
Palladin007
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1282
Erhaltene Danke: 182

Windows 11 x64 Pro
C# (Visual Studio Preview)
BeitragVerfasst: 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4700
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: So 29.11.15 19:07 
oder unsafe code benutzt wie string.join :wink:
Palladin007
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1282
Erhaltene Danke: 182

Windows 11 x64 Pro
C# (Visual Studio Preview)
BeitragVerfasst: 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4700
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: 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.