Der beste Weg, um eine Zeichenfolge umzukehren

440

Ich musste gerade eine String-Umkehrfunktion in C # 2.0 schreiben (dh LINQ nicht verfügbar) und kam auf Folgendes:

public string Reverse(string text)
{
    char[] cArray = text.ToCharArray();
    string reverse = String.Empty;
    for (int i = cArray.Length - 1; i > -1; i--)
    {
        reverse += cArray[i];
    }
    return reverse;
}

Persönlich bin ich nicht verrückt nach der Funktion und bin überzeugt, dass es einen besseren Weg gibt, dies zu tun. Gibt es?

Kerl
quelle
51
Überraschend schwierig, wenn Sie angemessene internationale Unterstützung wünschen. Beispiel: Kroatisch / Serbisch haben zweistellige Buchstaben lj, nj usw. Die richtige Umkehrung von "ljudi" ist "idulj", NICHT "idujl". Ich bin sicher, es würde Ihnen viel schlechter gehen, wenn es um Arabisch, Thailändisch usw. geht
dbkk
Ich frage mich, ob es langsamer ist, eine Zeichenfolge zu verknüpfen, anstatt ein temporäres Array zu initialisieren und die Ergebnisse darin zu speichern und diese dann schließlich in eine Zeichenfolge umzuwandeln.
Der Muffin-Mann
2
Viel neuerer verwandter Thread: Eine Zeichenfolge mit Akzentzeichen umkehren?
Jeppe Stig Nielsen
5
Diese Frage könnte verbessert werden, indem definiert wird, was Sie unter "am besten" verstehen. Am schnellsten? Am besten lesbar? Am zuverlässigsten in verschiedenen Randfällen (Nullprüfungen, mehrere Sprachen usw.)? Am wartbarsten für Versionen von C # und .NET?
hypehuman

Antworten:

608
public static string Reverse( string s )
{
    char[] charArray = s.ToCharArray();
    Array.Reverse( charArray );
    return new string( charArray );
}
PeteT
quelle
16
sambo99: Unicode muss nicht erwähnt werden: Zeichen in C # sind Unicode-Zeichen, keine Bytes. Xor ist zwar schneller, aber abgesehen davon, dass es weit weniger lesbar ist, kann Array.Reverse () dies sogar intern verwenden.
Nick Johnson
27
@Arachnid: Tatsächlich sind Zeichen in C # UTF-16-Codeeinheiten. Zwei von ihnen sind erforderlich, um einen zusätzlichen Charakter darzustellen. Siehe jaggersoft.com/csharp_standard/9.4.1.htm .
Bradley Grainger
4
Ja, sambo99 Ich nehme an, Sie haben Recht, aber es ist ein ziemlich seltener Fall, UTF-32 zu verwenden. Und XOR ist nur für einen sehr kleinen Wertebereich schneller. Die richtige Antwort wäre, verschiedene Methoden für unterschiedliche Längen zu implementieren, nehme ich an. Dies ist jedoch klar und prägnant, was meiner Meinung nach von Vorteil ist.
PeteT
21
Unicode-Steuerzeichen machen diese Methode für nicht-lateinische Zeichensätze unbrauchbar. Siehe Jon Skeet Erklärung mit einer Sockenpuppe: codeblog.jonskeet.uk/2009/11/02/… (1/4 der Weg nach unten) oder das Video: vimeo.com/7516539
Callum Rogers
20
Ich hoffe, Sie begegnen keinen Ersatz- oder Kombinationszeichen.
Dalle
183

Hier eine Lösung, die den String richtig umkehrt "Les Mise\u0301rables"als "selbare\u0301siM seL". Dies sollte genauso wiedergegeben werden selbarésiM seL, nicht selbaŕesiM seL(beachten Sie die Position des Akzents), wie dies bei den meisten Implementierungen der Fall wäre, die auf Codeeinheiten ( Array.Reverseusw.) oder sogar Codepunkten basieren (Umkehrung mit besonderer Sorgfalt für Ersatzpaare).

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;

public static class Test
{
    private static IEnumerable<string> GraphemeClusters(this string s) {
        var enumerator = StringInfo.GetTextElementEnumerator(s);
        while(enumerator.MoveNext()) {
            yield return (string)enumerator.Current;
        }
    }
    private static string ReverseGraphemeClusters(this string s) {
        return string.Join("", s.GraphemeClusters().Reverse().ToArray());
    }

    public static void Main()
    {
        var s = "Les Mise\u0301rables";
        var r = s.ReverseGraphemeClusters();
        Console.WriteLine(r);
    }
}

(Und Live-Laufbeispiel hier: https://ideone.com/DqAeMJ )

Es verwendet einfach die .NET- API für die Iteration von Graphemclustern , die es seit jeher gibt, die jedoch anscheinend etwas "verborgen" ist.

R. Martinho Fernandes
quelle
10
+1 Eine der wenigen richtigen Antworten und viel eleganter und zukunftssicherer als alle anderen, IMO
sehe
Dies schlägt jedoch für einige vom Gebietsschema abhängige Dinge fehl.
R. Martinho Fernandes
7
Es ist lustig, wie die meisten anderen Antwortenden versuchen, MS von ansonsten falschen Ansätzen abzuhalten. Wie repräsentativ.
G. Stoynev
2
Es ist tatsächlich erheblich schneller, StringInfo (s) zu instanziieren, dann SubstringByTextElements (x, 1) zu durchlaufen und mit einem StringBuilder einen neuen String zu erstellen.
2
Es ist ein bisschen seltsam, dass Sie Jon Skeets Beispiel verwendet haben, das er Jahre zuvor gegeben hat. Codeblog.jonskeet.uk/2009/11/02/… Les Misérables (obwohl Jon keine Lösung erwähnte, listete er nur Probleme auf). Gut, dass Sie eine Lösung gefunden haben. Vielleicht hat Jon Skeet eine Zeitmaschine erfunden, ist auf 2009 zurückgegangen und hat das Problembeispiel veröffentlicht, das Sie in Ihrer Lösung verwendet haben.
Barlop
126

Dies stellt sich als überraschend schwierige Frage heraus.

Ich würde Array.Reverse für die meisten Fälle empfehlen, da es nativ codiert ist und sehr einfach zu warten und zu verstehen ist.

Es scheint StringBuilder in allen von mir getesteten Fällen zu übertreffen.

public string Reverse(string text)
{
   if (text == null) return null;

   // this was posted by petebob as well 
   char[] array = text.ToCharArray();
   Array.Reverse(array);
   return new String(array);
}

Es gibt einen zweiten Ansatz, der für bestimmte Zeichenfolgenlängen mit Xor schneller sein kann .

    public static string ReverseXor(string s)
    {
        if (s == null) return null;
        char[] charArray = s.ToCharArray();
        int len = s.Length - 1;

        for (int i = 0; i < len; i++, len--)
        {
            charArray[i] ^= charArray[len];
            charArray[len] ^= charArray[i];
            charArray[i] ^= charArray[len];
        }

        return new string(charArray);
    }

Hinweis Wenn Sie den vollständigen Unicode UTF16-Zeichensatz unterstützen möchten, lesen Sie dies . Und verwenden Sie stattdessen die Implementierung dort. Es kann weiter optimiert werden, indem einer der oben genannten Algorithmen verwendet wird und die Zeichenfolge durchlaufen wird, um sie zu bereinigen, nachdem die Zeichen umgekehrt wurden.

Hier ist ein Leistungsvergleich zwischen der StringBuilder-, Array.Reverse- und Xor-Methode.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;

namespace ConsoleApplication4
{
    class Program
    {
        delegate string StringDelegate(string s);

        static void Benchmark(string description, StringDelegate d, int times, string text)
        {
            Stopwatch sw = new Stopwatch();
            sw.Start();
            for (int j = 0; j < times; j++)
            {
                d(text);
            }
            sw.Stop();
            Console.WriteLine("{0} Ticks {1} : called {2} times.", sw.ElapsedTicks, description, times);
        }

        public static string ReverseXor(string s)
        {
            char[] charArray = s.ToCharArray();
            int len = s.Length - 1;

            for (int i = 0; i < len; i++, len--)
            {
                charArray[i] ^= charArray[len];
                charArray[len] ^= charArray[i];
                charArray[i] ^= charArray[len];
            }

            return new string(charArray);
        }

        public static string ReverseSB(string text)
        {
            StringBuilder builder = new StringBuilder(text.Length);
            for (int i = text.Length - 1; i >= 0; i--)
            {
                builder.Append(text[i]);
            }
            return builder.ToString();
        }

        public static string ReverseArray(string text)
        {
            char[] array = text.ToCharArray();
            Array.Reverse(array);
            return (new string(array));
        }

        public static string StringOfLength(int length)
        {
            Random random = new Random();
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < length; i++)
            {
                sb.Append(Convert.ToChar(Convert.ToInt32(Math.Floor(26 * random.NextDouble() + 65))));
            }
            return sb.ToString();
        }

        static void Main(string[] args)
        {

            int[] lengths = new int[] {1,10,15,25,50,75,100,1000,100000};

            foreach (int l in lengths)
            {
                int iterations = 10000;
                string text = StringOfLength(l);
                Benchmark(String.Format("String Builder (Length: {0})", l), ReverseSB, iterations, text);
                Benchmark(String.Format("Array.Reverse (Length: {0})", l), ReverseArray, iterations, text);
                Benchmark(String.Format("Xor (Length: {0})", l), ReverseXor, iterations, text);

                Console.WriteLine();    
            }

            Console.Read();
        }
    }
}

Hier sind die Ergebnisse:

26251 Ticks String Builder (Length: 1) : called 10000 times.
33373 Ticks Array.Reverse (Length: 1) : called 10000 times.
20162 Ticks Xor (Length: 1) : called 10000 times.

51321 Ticks String Builder (Length: 10) : called 10000 times.
37105 Ticks Array.Reverse (Length: 10) : called 10000 times.
23974 Ticks Xor (Length: 10) : called 10000 times.

66570 Ticks String Builder (Length: 15) : called 10000 times.
26027 Ticks Array.Reverse (Length: 15) : called 10000 times.
24017 Ticks Xor (Length: 15) : called 10000 times.

101609 Ticks String Builder (Length: 25) : called 10000 times.
28472 Ticks Array.Reverse (Length: 25) : called 10000 times.
35355 Ticks Xor (Length: 25) : called 10000 times.

161601 Ticks String Builder (Length: 50) : called 10000 times.
35839 Ticks Array.Reverse (Length: 50) : called 10000 times.
51185 Ticks Xor (Length: 50) : called 10000 times.

230898 Ticks String Builder (Length: 75) : called 10000 times.
40628 Ticks Array.Reverse (Length: 75) : called 10000 times.
78906 Ticks Xor (Length: 75) : called 10000 times.

312017 Ticks String Builder (Length: 100) : called 10000 times.
52225 Ticks Array.Reverse (Length: 100) : called 10000 times.
110195 Ticks Xor (Length: 100) : called 10000 times.

2970691 Ticks String Builder (Length: 1000) : called 10000 times.
292094 Ticks Array.Reverse (Length: 1000) : called 10000 times.
846585 Ticks Xor (Length: 1000) : called 10000 times.

305564115 Ticks String Builder (Length: 100000) : called 10000 times.
74884495 Ticks Array.Reverse (Length: 100000) : called 10000 times.
125409674 Ticks Xor (Length: 100000) : called 10000 times.

Es scheint, dass Xor für kurze Saiten schneller sein kann.

Sam Saffron
quelle
2
Das gibt keinen String zurück - Sie müssen dies in einen Aufruf von "new String (...)"
Greg Beech
Übrigens ... Ich habe mir gerade die Implementierung von Array.Reverse angesehen und es ist naiv für Zeichen gemacht ... es sollte viel schneller sein als die StringBuilder-Option.
Sam Saffron
Wie nett von dir, Greg, Sambo zu halpen, um eine bessere Lösung zu finden, anstatt ihn herunterzustimmen.
DOK
@ dok1 - erwähne es nicht :) @ sambo99 - jetzt bin ich fasziniert, muss morgen einen Code-Profiler auspeitschen und schauen!
Greg Beech
9
Diese Methoden verarbeiten keine Zeichenfolgen, die Zeichen außerhalb der mehrsprachigen Basisebene enthalten, dh Unicode-Zeichen> = U + 10000, die mit zwei C # -Zeichen dargestellt werden. Ich habe eine Antwort gepostet, die solche Zeichenfolgen korrekt behandelt.
Bradley Grainger
52

Wenn Sie LINQ (.NET Framework 3.5+) verwenden können, erhalten Sie einen folgenden Code, wenn Sie einem Liner folgen. Vergessen Sie nicht hinzuzufügen using System.Linq;, um Zugriff zu haben auf Enumerable.Reverse:

public string ReverseString(string srtVarable)
{
    return new string(srtVarable.Reverse().ToArray());
}

Anmerkungen:

  • nicht die schnellste Version - laut Martin Niederl 5,7 mal langsamer als die schnellste Wahl hier.
  • Dieser Code ignoriert wie viele andere Optionen alle Arten von Kombinationen aus mehreren Zeichen vollständig. Beschränken Sie die Verwendung daher auf Hausaufgaben und Zeichenfolgen, die solche Zeichen nicht enthalten. Eine andere Antwort in dieser Frage finden Sie zur Implementierung, die solche Kombinationen korrekt verarbeitet.
SGRao
quelle
Das ist ungefähr 5,7-mal langsamer als die am besten bewertete Version, daher würde ich die Verwendung nicht empfehlen!
Martin Niederl
2
Nicht die schnellste Lösung, aber nützlich als Einzeiler.
Adrianmp
49

Wenn die Zeichenfolge Unicode-Daten enthält (streng genommen Nicht-BMP-Zeichen), wird sie durch die anderen veröffentlichten Methoden beschädigt, da Sie beim Umkehren der Zeichenfolge die Reihenfolge der Ersatzcodeeinheiten für hohe und niedrige Werte nicht vertauschen können. (Weitere Informationen hierzu finden Sie in meinem Blog .)

Das folgende Codebeispiel kehrt eine Zeichenfolge korrekt um, die Nicht-BMP-Zeichen enthält, z. B. "\ U00010380 \ U00010381" (Ugaritic Letter Alpa, Ugaritic Letter Beta).

public static string Reverse(this string input)
{
    if (input == null)
        throw new ArgumentNullException("input");

    // allocate a buffer to hold the output
    char[] output = new char[input.Length];
    for (int outputIndex = 0, inputIndex = input.Length - 1; outputIndex < input.Length; outputIndex++, inputIndex--)
    {
        // check for surrogate pair
        if (input[inputIndex] >= 0xDC00 && input[inputIndex] <= 0xDFFF &&
            inputIndex > 0 && input[inputIndex - 1] >= 0xD800 && input[inputIndex - 1] <= 0xDBFF)
        {
            // preserve the order of the surrogate pair code units
            output[outputIndex + 1] = input[inputIndex];
            output[outputIndex] = input[inputIndex - 1];
            outputIndex++;
            inputIndex--;
        }
        else
        {
            output[outputIndex] = input[inputIndex];
        }
    }

    return new string(output);
}
Bradley Grainger
quelle
29
Tatsächlich sind Zeichen in C # 16-Bit-UTF-16-Codeeinheiten. Ein zusätzliches Zeichen wird mit zwei von ihnen codiert, daher ist dies notwendig.
Bradley Grainger
14
Es scheint, dass System.String wirklich eine HereBeDragons-Eigenschaft für Zeichenfolgen verfügbar machen sollte, die zusätzliche Unicode-Zeichen enthalten.
Robert Rossney
4
@SebastianNegraszus: Das ist richtig: Diese Methode kehrt nur die Codepunkte in der Zeichenfolge um. Das Umkehren der Graphemcluster wäre wahrscheinlich insgesamt "nützlicher" (aber was nützt es überhaupt, eine beliebige Zeichenfolge umzukehren?), Ist jedoch nicht einfach mit nur den in .NET Framework integrierten Methoden zu implementieren.
Bradley Grainger
2
@Richard: Die Regeln zum Aufbrechen von Graphemclustern sind etwas komplizierter als nur das Erkennen kombinierter Codepunkte. Weitere Informationen finden Sie in der Dokumentation zu Grapheme Cluster Boundaries in UAX # 29.
Bradley Grainger
1
Sehr gute Infos! Hat jemand einen fehlgeschlagenen Test für den Array.Reverse-Test? Und mit Test meine ich eine Beispielzeichenfolge, nicht einen ganzen
Komponententest
25

Ok, im Interesse von "Wiederhole dich nicht" biete ich die folgende Lösung an:

public string Reverse(string text)
{
   return Microsoft.VisualBasic.Strings.StrReverse(text);
}

Nach meinem Verständnis verarbeitet diese Implementierung, die standardmäßig in VB.NET verfügbar ist, Unicode-Zeichen ordnungsgemäß.

richardtallent
quelle
11
Dies behandelt nur Ersatzzeichen richtig. Das Kombinieren von Marken bringt es durcheinander : ideone.com/yikdqX .
R. Martinho Fernandes
17

Greg Beech hat eine unsafeOption veröffentlicht, die in der Tat so schnell wie möglich ist (es handelt sich um eine direkte Umkehrung). Aber wie er in seiner Antwort angedeutet hat, ist es eine völlig katastrophale Idee .

Trotzdem bin ich überrascht, dass es so viel Konsens gibt, dass dies Array.Reversedie schnellste Methode ist. Es gibt immer noch einen unsafeAnsatz, der eine umgekehrte Kopie eines Strings (keine direkten Umkehrshenanigans) signifikant schnellerArray.Reverse zurückgibt als die Methode für kleine Strings:

public static unsafe string Reverse(string text)
{
    int len = text.Length;

    // Why allocate a char[] array on the heap when you won't use it
    // outside of this method? Use the stack.
    char* reversed = stackalloc char[len];

    // Avoid bounds-checking performance penalties.
    fixed (char* str = text)
    {
        int i = 0;
        int j = i + len - 1;
        while (i < len)
        {
            reversed[i++] = str[j--];
        }
    }

    // Need to use this overload for the System.String constructor
    // as providing just the char* pointer could result in garbage
    // at the end of the string (no guarantee of null terminator).
    return new string(reversed, 0, len);
}

Hier sind einige Benchmark-Ergebnisse .

Sie können sehen, dass der Leistungsgewinn abnimmt und dann gegenüber der Array.ReverseMethode verschwindet , wenn die Zeichenfolgen größer werden. Bei kleinen bis mittelgroßen Saiten ist diese Methode jedoch schwer zu übertreffen.

Dan Tao
quelle
2
StackOverflow auf großen Strings.
Raz Megrelidze
@rezomegreldize: Ja, das wird passieren;)
Dan Tao
15

Die einfache und nette Antwort ist die Verwendung der Erweiterungsmethode:

static class ExtentionMethodCollection
{
    public static string Inverse(this string @base)
    {
        return new string(@base.Reverse().ToArray());
    }
}

und hier ist die Ausgabe:

string Answer = "12345".Inverse(); // = "54321"
Mehdi Khademloo
quelle
Reverse()und ToArray()sind in der falschen Reihenfolge in Ihrem Codebeispiel.
Chris Walsh
Welchen Zweck erfüllt das @?
user5389726598465
2
@ user5389726598465 Siehe diesen Link: docs.microsoft.com/en-us/dotnet/csharp/language-reference/… Da 'base' ein Schlüsselwort in C # ist, muss @ vorangestellt werden, damit der C # -Compiler es als interpretiert Kennung.
Dyndrilliac
14

Wenn Sie ein wirklich gefährliches Spiel spielen möchten, ist dies bei weitem der schnellste Weg (ungefähr viermal schneller als die Array.ReverseMethode). Es ist eine direkte Umkehrung mit Zeigern.

Beachten Sie, dass ich dies wirklich niemals für irgendeine Verwendung empfehle ( sehen Sie sich hier einige Gründe an, warum Sie diese Methode nicht verwenden sollten ), aber es ist nur interessant zu sehen, dass dies möglich ist und dass Zeichenfolgen nicht wirklich unveränderlich sind Sobald Sie unsicheren Code einschalten.

public static unsafe string Reverse(string text)
{
    if (string.IsNullOrEmpty(text))
    {
        return text;
    }

    fixed (char* pText = text)
    {
        char* pStart = pText;
        char* pEnd = pText + text.Length - 1;
        for (int i = text.Length / 2; i >= 0; i--)
        {
            char temp = *pStart;
            *pStart++ = *pEnd;
            *pEnd-- = temp;
        }

        return text;
    }
}
Greg Beech
quelle
Ich bin mir ziemlich sicher, dass dies falsche Ergebnisse für utf16-Strings zurückgibt, es ist wirklich problematisch :)
Sam Saffron
Hallo, Sie sollten auf diesen Beitrag auf diesem stackoverflow.com/questions/229346/… verlinken , wie ich bereits sagte, dies ist wirklich problematisch ...
Sam Saffron
Dies mag völlig böse und schlecht beraten sein (wie Sie selbst zugeben), aber es gibt immer noch eine leistungsstarke Möglichkeit, eine Zeichenfolge mit unsafeCode umzukehren , der nicht böse ist und in vielen Fällen immer noch schlägt Array.Reverse. Schauen Sie sich meine Antwort an.
Dan Tao
13

Schauen Sie sich hier den Wikipedia-Eintrag an . Sie implementieren die Erweiterungsmethode String.Reverse. Auf diese Weise können Sie Code wie folgt schreiben:

string s = "olleh";
s.Reverse();

Sie verwenden auch die Kombination ToCharArray / Reverse, die andere Antworten auf diese Frage vorschlagen. Der Quellcode sieht folgendermaßen aus:

public static string Reverse(this string input)
{
    char[] chars = input.ToCharArray();
    Array.Reverse(chars);
    return new String(chars);
}
Mike Thompson
quelle
Das ist wunderbar, außer dass Erweiterungsmethoden in c # 2.0 nicht eingeführt wurden.
Kobi
11

Erstens müssen Sie nicht aufrufen, ToCharArrayda eine Zeichenfolge bereits als Zeichenarray indiziert werden kann, sodass Sie eine Zuordnung sparen.

Die nächste Optimierung besteht darin, a StringBuilderzu verwenden, um unnötige Zuordnungen zu vermeiden (da Zeichenfolgen unveränderlich sind, wird durch Verketten jedes Mal eine Kopie der Zeichenfolge erstellt). Um dies weiter zu optimieren, haben wir die Länge des voreingestellt, damit der StringBuilderPuffer nicht erweitert werden muss.

public string Reverse(string text)
{
    if (string.IsNullOrEmpty(text))
    {
        return text;
    }

    StringBuilder builder = new StringBuilder(text.Length);
    for (int i = text.Length - 1; i >= 0; i--)
    {
        builder.Append(text[i]);
    }

    return builder.ToString();
}

Bearbeiten: Leistungsdaten

Ich habe diese Funktion und die Funktion Array.Reversemit dem folgenden einfachen Programm getestet , wobei Reverse1eine Funktion und Reverse2die andere ist:

static void Main(string[] args)
{
    var text = "abcdefghijklmnopqrstuvwxyz";

    // pre-jit
    text = Reverse1(text); 
    text = Reverse2(text);

    // test
    var timer1 = Stopwatch.StartNew();
    for (var i = 0; i < 10000000; i++)
    {
        text = Reverse1(text);
    }

    timer1.Stop();
    Console.WriteLine("First: {0}", timer1.ElapsedMilliseconds);

    var timer2 = Stopwatch.StartNew();
    for (var i = 0; i < 10000000; i++)
    {
        text = Reverse2(text);
    }

    timer2.Stop();
    Console.WriteLine("Second: {0}", timer2.ElapsedMilliseconds);

    Console.ReadLine();
}

Es stellt sich heraus, dass die Array.ReverseMethode für kurze Zeichenfolgen etwa doppelt so schnell ist wie die oben beschriebene, und für längere Zeichenfolgen ist der Unterschied noch ausgeprägter. Da die Array.ReverseMethode sowohl einfacher als auch schneller ist, würde ich empfehlen, dass Sie diese anstelle dieser verwenden. Ich lasse dieses hier oben, nur um zu zeigen, dass es nicht so ist, wie du es tun solltest (sehr zu meiner Überraschung!)

Greg Beech
quelle
Würde das Speichern von Text nicht die Länge einer Variablen erhöhen, wenn Sie dies über ein Objekt referenzieren?
David Robbins
10

Versuchen Sie es mit Array.Reverse


public string Reverse(string str)
{
    char[] array = str.ToCharArray();
    Array.Reverse(array);
    return new string(array);
}
Mike Zwei
quelle
Das ist unglaublich schnell.
Michael Stum
Warum die Abwahl? Ich streite nicht darüber, aber ich würde lieber aus meinen Fehlern lernen.
Mike Two
Das Kombinieren von Codepunkten ist unter anderem nicht möglich.
Mooing Duck
@MooingDuck - danke für die Erklärung, aber ich weiß nicht, was du mit Codepunkten meinst. Könnten Sie auch "viele andere Dinge" näher erläutern?
Mike Two
@MooingDuck Ich habe nach Codepunkten gesucht. Ja. Du hast Recht. Codepunkte werden nicht verarbeitet. Es ist schwierig, alle Anforderungen für eine so einfach aussehende Frage zu ermitteln. Vielen Dank für das Feedback
Mike Two
10
public static string Reverse(string input)
{
    return string.Concat(Enumerable.Reverse(input));
}

Natürlich können Sie die Zeichenfolgenklasse mit der Reverse-Methode erweitern

public static class StringExtensions
{
    public static string Reverse(this string input)
    {
        return string.Concat(Enumerable.Reverse(input));
    }
}
Vlad Bezden
quelle
Enumerable.Reverse(input)ist gleichinput.Reverse()
fubo
8

"Best" kann von vielen Dingen abhängen, aber hier sind einige weitere kurze Alternativen, die von schnell bis langsam geordnet sind:

string s = "z̽a̎l͘g̈o̓😀😆", pattern = @"(?s).(?<=(?:.(?=.*$(?<=((\P{M}\p{C}?\p{M}*)\1?))))*)";

string s1 = string.Concat(s.Reverse());                          // "☐😀☐̓ög͘l̎a̽z"  👎

string s2 = Microsoft.VisualBasic.Strings.StrReverse(s);         // "😆😀o̓g̈l͘a̎̽z"  👌

string s3 = string.Concat(StringInfo.ParseCombiningCharacters(s).Reverse()
    .Select(i => StringInfo.GetNextTextElement(s, i)));          // "😆😀o̓g̈l͘a̎z̽"  👍

string s4 = Regex.Replace(s, pattern, "$2").Remove(s.Length);    // "😆😀o̓g̈l͘a̎z̽"  👍
Slai
quelle
8

Ab .NET Core 2.1 gibt es eine neue Möglichkeit, eine Zeichenfolge mithilfe der string.CreateMethode umzukehren .

Beachten Sie, dass diese Lösung Unicode-Kombinationszeichen usw. nicht korrekt verarbeitet, da "Les Mise \ u0301rables" in "selbarésiM seL" konvertiert wird. Die anderen Antworten für eine bessere Lösung.

public static string Reverse(string input)
{
    return string.Create<string>(input.Length, input, (chars, state) =>
    {
        state.AsSpan().CopyTo(chars);
        chars.Reverse();
    });
}

Dies kopiert im Wesentlichen die Zeichen von inputin eine neue Zeichenfolge und kehrt die neue Zeichenfolge an Ort und Stelle um.

Warum ist string.Createnützlich?

Wenn wir eine Zeichenfolge aus einem vorhandenen Array erstellen, wird ein neues internes Array zugewiesen und die Werte werden kopiert. Andernfalls wäre es möglich, eine Zeichenfolge nach ihrer Erstellung zu mutieren (in einer sicheren Umgebung). Das heißt, im folgenden Snippet müssen wir ein Array mit der Länge 10 zweimal zuweisen, eines als Puffer und eines als internes Array der Zeichenfolge.

var chars = new char[10];
// set array values
var str = new string(chars);

string.CreateIm Wesentlichen können wir das interne Array während der Erstellungszeit des Strings bearbeiten. Dies bedeutet, dass wir keinen Puffer mehr benötigen und daher die Zuweisung dieses einen Zeichenarrays vermeiden können.

Steve Gordon hat hier ausführlicher darüber geschrieben . Es gibt auch einen Artikel über MSDN .

Wie benutzt man string.Create?

public static string Create<TState>(int length, TState state, SpanAction<char, TState> action);

Die Methode akzeptiert drei Parameter:

  1. Die Länge der zu erstellenden Zeichenfolge,
  2. die Daten, die Sie zum dynamischen Erstellen der neuen Zeichenfolge verwenden möchten,
  3. und ein Delegat, der die endgültige Zeichenfolge aus den Daten erstellt, wobei der erste Parameter auf das interne charArray der neuen Zeichenfolge verweist und der zweite die Daten (Status) ist, an die Sie übergeben haben string.Create.

Innerhalb des Delegaten können wir angeben, wie die neue Zeichenfolge aus den Daten erstellt wird. In unserem Fall kopieren wir einfach die Zeichen der Eingabezeichenfolge in die Spanvon der neuen Zeichenfolge verwendete. Dann kehren wir das um Spanund daher wird die gesamte Zeichenfolge umgekehrt.

Benchmarks

Um meine vorgeschlagene Methode zum Umkehren einer Zeichenfolge mit der akzeptierten Antwort zu vergleichen, habe ich zwei Benchmarks mit BenchmarkDotNet geschrieben.

public class StringExtensions
{
    public static string ReverseWithArray(string input)
    {
        var charArray = input.ToCharArray();
        Array.Reverse(charArray);
        return new string(charArray);
    }

    public static string ReverseWithStringCreate(string input)
    {
        return string.Create(input.Length, input, (chars, state) =>
        {
            state.AsSpan().CopyTo(chars);
            chars.Reverse();
        });
    }
}

[MemoryDiagnoser]
public class StringReverseBenchmarks
{
    private string input;

    [Params(10, 100, 1000)]
    public int InputLength { get; set; }


    [GlobalSetup]
    public void SetInput()
    {
        // Creates a random string of the given length
        this.input = RandomStringGenerator.GetString(InputLength);
    }

    [Benchmark(Baseline = true)]
    public string WithReverseArray() => StringExtensions.ReverseWithArray(input);

    [Benchmark]
    public string WithStringCreate() => StringExtensions.ReverseWithStringCreate(input);
}

Hier sind die Ergebnisse auf meiner Maschine:

| Method           | InputLength |         Mean |      Error |    StdDev |  Gen 0 | Allocated |
| ---------------- | ----------- | -----------: | ---------: | --------: | -----: | --------: |
| WithReverseArray | 10          |    45.464 ns |  0.4836 ns | 0.4524 ns | 0.0610 |      96 B |
| WithStringCreate | 10          |    39.749 ns |  0.3206 ns | 0.2842 ns | 0.0305 |      48 B |
|                  |             |              |            |           |        |           |
| WithReverseArray | 100         |   175.162 ns |  2.8766 ns | 2.2458 ns | 0.2897 |     456 B |
| WithStringCreate | 100         |   125.284 ns |  2.4657 ns | 2.0590 ns | 0.1473 |     232 B |
|                  |             |              |            |           |        |           |
| WithReverseArray | 1000        | 1,523.544 ns |  9.8808 ns | 8.7591 ns | 2.5768 |    4056 B |
| WithStringCreate | 1000        | 1,078.957 ns | 10.2948 ns | 9.6298 ns | 1.2894 |    2032 B |

Wie Sie sehen können, ReverseWithStringCreateweisen wir nur die Hälfte des von der ReverseWithArrayMethode verwendeten Speichers zu .

Flogex
quelle
Es ist viel schneller als Linq Reverse
Code4j
7

Kümmere dich nicht um eine Funktion, sondern mache sie einfach an Ort und Stelle. Hinweis: In der zweiten Zeile wird bei einigen VS-Versionen eine Argumentausnahme im Direktfenster ausgelöst.

string s = "Blah";
s = new string(s.ToCharArray().Reverse().ToArray()); 
BH
quelle
1
Ein Typ hat sich die Zeit genommen, jede Antwort (meine eingeschlossen) herunterzustimmen, ohne zu erklären, warum.
Marcel Valdez Orozco
Dies ist nicht wirklich vorhanden, da Sie einnew string
mbadawi23
5

Entschuldigung für den langen Beitrag, aber das könnte interessant sein

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;

namespace ConsoleApplication1
{
    class Program
    {
        public static string ReverseUsingArrayClass(string text)
        {
            char[] chars = text.ToCharArray();
            Array.Reverse(chars);
            return new string(chars);
        }

        public static string ReverseUsingCharacterBuffer(string text)
        {
            char[] charArray = new char[text.Length];
            int inputStrLength = text.Length - 1;
            for (int idx = 0; idx <= inputStrLength; idx++) 
            {
                charArray[idx] = text[inputStrLength - idx];                
            }
            return new string(charArray);
        }

        public static string ReverseUsingStringBuilder(string text)
        {
            if (string.IsNullOrEmpty(text))
            {
                return text;
            }

            StringBuilder builder = new StringBuilder(text.Length);
            for (int i = text.Length - 1; i >= 0; i--)
            {
                builder.Append(text[i]);
            }

            return builder.ToString();
        }

        private static string ReverseUsingStack(string input)
        {
            Stack<char> resultStack = new Stack<char>();
            foreach (char c in input)
            {
                resultStack.Push(c);
            }

            StringBuilder sb = new StringBuilder();
            while (resultStack.Count > 0)
            {
                sb.Append(resultStack.Pop());
            }
            return sb.ToString();
        }

        public static string ReverseUsingXOR(string text)
        {
            char[] charArray = text.ToCharArray();
            int length = text.Length - 1;
            for (int i = 0; i < length; i++, length--)
            {
                charArray[i] ^= charArray[length];
                charArray[length] ^= charArray[i];
                charArray[i] ^= charArray[length];
            }

            return new string(charArray);
        }


        static void Main(string[] args)
        {
            string testString = string.Join(";", new string[] {
                new string('a', 100), 
                new string('b', 101), 
                new string('c', 102), 
                new string('d', 103),                                                                   
            });
            int cycleCount = 100000;

            Stopwatch stopwatch = new Stopwatch();
            stopwatch.Start();
            for (int i = 0; i < cycleCount; i++) 
            {
                ReverseUsingCharacterBuffer(testString);
            }
            stopwatch.Stop();
            Console.WriteLine("ReverseUsingCharacterBuffer: " + stopwatch.ElapsedMilliseconds + "ms");

            stopwatch.Reset();
            stopwatch.Start();
            for (int i = 0; i < cycleCount; i++) 
            {
                ReverseUsingArrayClass(testString);
            }
            stopwatch.Stop();
            Console.WriteLine("ReverseUsingArrayClass: " + stopwatch.ElapsedMilliseconds + "ms");

            stopwatch.Reset();
            stopwatch.Start();
            for (int i = 0; i < cycleCount; i++) 
            {
                ReverseUsingStringBuilder(testString);
            }
            stopwatch.Stop();
            Console.WriteLine("ReverseUsingStringBuilder: " + stopwatch.ElapsedMilliseconds + "ms");

            stopwatch.Reset();
            stopwatch.Start();
            for (int i = 0; i < cycleCount; i++) 
            {
                ReverseUsingStack(testString);
            }
            stopwatch.Stop();
            Console.WriteLine("ReverseUsingStack: " + stopwatch.ElapsedMilliseconds + "ms");

            stopwatch.Reset();
            stopwatch.Start();
            for (int i = 0; i < cycleCount; i++) 
            {
                ReverseUsingXOR(testString);
            }
            stopwatch.Stop();
            Console.WriteLine("ReverseUsingXOR: " + stopwatch.ElapsedMilliseconds + "ms");            
        }
    }
}

Ergebnisse:

  • ReverseUsingCharacterBuffer: 346 ms
  • ReverseUsingArrayClass: 87 ms
  • ReverseUsingStringBuilder: 824 ms
  • ReverseUsingStack: 2086 ms
  • ReverseUsingXOR: 319 ms
aku
quelle
Ich habe in meinem Beitrag einen ähnlichen Vergleich hinzugefügt. Es handelt sich um ein Community-Wiki, damit Sie es bearbeiten können. Die Leistung hängt wirklich von der Länge des Strings sowie vom Algorithmus ab. Es wäre interessant, ihn grafisch darzustellen. Ich denke immer noch, Array.Reverse wird in allen Fällen am schnellsten sein ...
Sam Saffron
"wird in allen Fällen am schnellsten sein", wenn die magische TrySZReverse-Funktion (die in der umgekehrten Implementierung verwendet wird) fehlschlägt, Array.Reverse greift auf eine einfache Implementierung mit Boxen zurück, sodass meine Methode gewinnt. Ich weiß jedoch nicht, unter welchen Bedingungen TrySZReverse fehlschlägt.
Aku
Es stellt sich heraus, dass es nicht in allen Fällen am schnellsten ist :), ich habe meinen Beitrag aktualisiert. Dies muss noch mit Unicode auf Richtigkeit und Geschwindigkeit getestet werden.
Sam Saffron
5
public string Reverse(string input)
{
    char[] output = new char[input.Length];

    int forwards = 0;
    int backwards = input.Length - 1;

    do
    {
        output[forwards] = input[backwards];
        output[backwards] = input[forwards];
    }while(++forwards <= --backwards);

    return new String(output);
}

public string DotNetReverse(string input)
{
    char[] toReverse = input.ToCharArray();
    Array.Reverse(toReverse);
    return new String(toReverse);
}

public string NaiveReverse(string input)
{
    char[] outputArray = new char[input.Length];
    for (int i = 0; i < input.Length; i++)
    {
        outputArray[i] = input[input.Length - 1 - i];
    }

    return new String(outputArray);
}    

public string RecursiveReverse(string input)
{
    return RecursiveReverseHelper(input, 0, input.Length - 1);
}

public string RecursiveReverseHelper(string input, int startIndex , int endIndex)
{
    if (startIndex == endIndex)
    {
        return "" + input[startIndex];
    }

    if (endIndex - startIndex == 1)
    {
        return "" + input[endIndex] + input[startIndex];
    }

    return input[endIndex] + RecursiveReverseHelper(input, startIndex + 1, endIndex - 1) + input[startIndex];
}


void Main()
{
    int[] sizes = new int[] { 10, 100, 1000, 10000 };
    for(int sizeIndex = 0; sizeIndex < sizes.Length; sizeIndex++)
    {
        string holaMundo  = "";
        for(int i = 0; i < sizes[sizeIndex]; i+= 5)
        {   
            holaMundo += "ABCDE";
        }

        string.Format("\n**** For size: {0} ****\n", sizes[sizeIndex]).Dump();

        string odnuMaloh = DotNetReverse(holaMundo);

        var stopWatch = Stopwatch.StartNew();
        string result = NaiveReverse(holaMundo);
        ("Naive Ticks: " + stopWatch.ElapsedTicks).Dump();

        stopWatch.Restart();
        result = Reverse(holaMundo);
        ("Efficient linear Ticks: " + stopWatch.ElapsedTicks).Dump();

        stopWatch.Restart();
        result = RecursiveReverse(holaMundo);
        ("Recursive Ticks: " + stopWatch.ElapsedTicks).Dump();

        stopWatch.Restart();
        result = DotNetReverse(holaMundo);
        ("DotNet Reverse Ticks: " + stopWatch.ElapsedTicks).Dump();
    }
}

Ausgabe

Für Größe: 10

Naive Ticks: 1
Efficient linear Ticks: 0
Recursive Ticks: 2
DotNet Reverse Ticks: 1

Für Größe: 100

Naive Ticks: 2
Efficient linear Ticks: 1
Recursive Ticks: 12
DotNet Reverse Ticks: 1

Für Größe: 1000

Naive Ticks: 5
Efficient linear Ticks: 2
Recursive Ticks: 358
DotNet Reverse Ticks: 9

Für Größe: 10000

Naive Ticks: 32
Efficient linear Ticks: 28
Recursive Ticks: 84808
DotNet Reverse Ticks: 33
Marcel Valdez Orozco
quelle
1
Sie müssen nach leeren Zeichenfolgen suchen Reverse(...). Ansonsten gute Arbeit.
Lara
5

Einfachster Weg:

string reversed = new string(text.Reverse().ToArray());
Schattiger Sirhan
quelle
Ich benutze den gleichen Satz
VhsPiceros
4

Stapelbasierte Lösung.

    public static string Reverse(string text)
    {
        var stack = new Stack<char>(text);
        var array = new char[stack.Count];

        int i = 0;
        while (stack.Count != 0)
        {
            array[i++] = stack.Pop();
        }

        return new string(array);
    }

Oder

    public static string Reverse(string text)
    {
        var stack = new Stack<char>(text);
        return string.Join("", stack);
    }
Raz Megrelidze
quelle
4

Musste ein rekursives Beispiel einreichen:

private static string Reverse(string str)
{
    if (str.IsNullOrEmpty(str) || str.Length == 1)
        return str;
    else
        return str[str.Length - 1] + Reverse(str.Substring(0, str.Length - 1));
}
JPrescottSanders
quelle
1
Zeichenfolge der Länge 0 werden nicht behandelt
bohdan_trotsenko
Das ist nicht sinnvoll.
user3613932
3

Wie wäre es mit:

    private string Reverse(string stringToReverse)
    {
        char[] rev = stringToReverse.Reverse().ToArray();
        return new string(rev); 
    }
Zamir
quelle
Hat die gleichen Codepoint-Probleme wie andere oben beschriebene Methoden und arbeitet viel langsamer als bei einer ToCharArrayersten. Der LINQ-Enumerator ist auch viel langsamer als Array.Reverse().
Abel
3

Ich habe einen C # -Port aus Microsoft.VisualBasic.Strings erstellt . Ich bin nicht sicher, warum sie solche nützlichen Funktionen (von VB) außerhalb von System.String in Framework behalten, aber immer noch unter Microsoft.VisualBasic. Gleiches Szenario für Finanzfunktionen (z Microsoft.VisualBasic.Financial.Pmt(). B. ).

public static string StrReverse(this string expression)
{
    if ((expression == null))
        return "";

    int srcIndex;

    var length = expression.Length;
    if (length == 0)
        return "";

    //CONSIDER: Get System.String to add a surrogate aware Reverse method

    //Detect if there are any graphemes that need special handling
    for (srcIndex = 0; srcIndex <= length - 1; srcIndex++)
    {
        var ch = expression[srcIndex];
        var uc = char.GetUnicodeCategory(ch);
        if (uc == UnicodeCategory.Surrogate || uc == UnicodeCategory.NonSpacingMark || uc == UnicodeCategory.SpacingCombiningMark || uc == UnicodeCategory.EnclosingMark)
        {
            //Need to use special handling
            return InternalStrReverse(expression, srcIndex, length);
        }
    }

    var chars = expression.ToCharArray();
    Array.Reverse(chars);
    return new string(chars);
}

///<remarks>This routine handles reversing Strings containing graphemes
/// GRAPHEME: a text element that is displayed as a single character</remarks>
private static string InternalStrReverse(string expression, int srcIndex, int length)
{
    //This code can only be hit one time
    var sb = new StringBuilder(length) { Length = length };

    var textEnum = StringInfo.GetTextElementEnumerator(expression, srcIndex);

    //Init enumerator position
    if (!textEnum.MoveNext())
    {
        return "";
    }

    var lastSrcIndex = 0;
    var destIndex = length - 1;

    //Copy up the first surrogate found
    while (lastSrcIndex < srcIndex)
    {
        sb[destIndex] = expression[lastSrcIndex];
        destIndex -= 1;
        lastSrcIndex += 1;
    }

    //Now iterate through the text elements and copy them to the reversed string
    var nextSrcIndex = textEnum.ElementIndex;

    while (destIndex >= 0)
    {
        srcIndex = nextSrcIndex;

        //Move to next element
        nextSrcIndex = (textEnum.MoveNext()) ? textEnum.ElementIndex : length;
        lastSrcIndex = nextSrcIndex - 1;

        while (lastSrcIndex >= srcIndex)
        {
            sb[destIndex] = expression[lastSrcIndex];
            destIndex -= 1;
            lastSrcIndex -= 1;
        }
    }

    return sb.ToString();
}
natenho
quelle
+1, eine schöne Ergänzung! Ich habe es gerade mit versucht string s = "abo\u0327\u0307\u035d\U0001d166cd", der den Buchstaben enthält, ogefolgt von 3 kombinierten diakritischen Markierungen im BMP und einer Kombinationsmarkierung (MUSICAL SYMBOL COMBINING STEM) von der Astralebene (Nicht-BMP) und sie intakt hält. Die Methode ist jedoch langsam, wenn solche Zeichen nur am Ende einer langen Zeichenfolge angezeigt werden, da sie das gesamte Array zweimal durchlaufen muss.
Abel
3

Entschuldigung für die Veröffentlichung in diesem alten Thread. Ich übe einen Code für ein Interview.

Das habe ich mir für C # ausgedacht. Meine erste Version vor dem Refactoring war schrecklich.

static String Reverse2(string str)
{
    int strLen = str.Length, elem = strLen - 1;
    char[] charA = new char[strLen];

    for (int i = 0; i < strLen; i++)
    {
        charA[elem] = str[i];
        elem--;
    }

    return new String(charA);
}

Im Gegensatz zur folgenden Array.ReverseMethode wird es mit maximal 12 Zeichen in der Zeichenfolge schneller angezeigt. Nach 13 Zeichen wird das Array.Reverseschneller und es dominiert schließlich ziemlich stark die Geschwindigkeit. Ich wollte nur ungefähr darauf hinweisen, wo sich die Geschwindigkeit zu ändern beginnt.

static String Reverse(string str)
{     
    char[] charA = str.ToCharArray();

    Array.Reverse(charA);

    return new String(charA);
}

Mit 100 Zeichen in der Zeichenfolge ist es schneller als meine Version x 4. Wenn ich jedoch wüsste, dass die Zeichenfolgen immer weniger als 13 Zeichen umfassen würden, würde ich die von mir erstellte verwenden.

Das Testen wurde mit Stopwatchund 5000000 Iterationen durchgeführt. Ich bin mir auch nicht sicher, ob meine Version Ersatzsituationen oder kombinierte Zeichensituationen mit UnicodeCodierung behandelt.

Jason Ausborn
quelle
2

"Besserer Weg" hängt davon ab, was für Sie in Ihrer Situation, Leistung, Eleganz, Wartbarkeit usw. wichtiger ist.

Wie auch immer, hier ist ein Ansatz mit Array.Reverse:

string inputString="The quick brown fox jumps over the lazy dog.";
char[] charArray = inputString.ToCharArray(); 
Array.Reverse(charArray); 

string reversed = new string(charArray);
Asche
quelle
2

Wenn es jemals in einem Interview auftauchte und Ihnen gesagt wurde, dass Sie Array.Reverse nicht verwenden können, denke ich, dass dies eines der schnellsten sein könnte. Es werden keine neuen Zeichenfolgen erstellt und nur über die Hälfte des Arrays iteriert (dh O (n / 2) -Iterationen).

    public static string ReverseString(string stringToReverse)
    {
        char[] charArray = stringToReverse.ToCharArray();
        int len = charArray.Length-1;
        int mid = len / 2;

        for (int i = 0; i < mid; i++)
        {
            char tmp = charArray[i];
            charArray[i] = charArray[len - i];
            charArray[len - i] = tmp;
        }
        return new string(charArray);
    }
mike01010
quelle
2
Ich bin mir ziemlich sicher, dass der Aufruf von stringToReverse.ToCharArray () eine Ausführungszeit von O (N) erzeugt.
Marcel Valdez Orozco
In der Big-O-Notation wird der Faktor, der nicht von xoder in Ihrem Fall abhängig nist, nicht verwendet. Ihr Algorithmus hat eine Leistung f(x) = x + ½x + C, wobei C eine Konstante ist. Da beide Cund der Faktor nicht abhängig sind x, ist Ihr Algorithmus O(x). Das bedeutet nicht, dass es für eine Eingabe der Länge nicht schneller ist x, aber seine Leistung hängt linear von der Eingabelänge ab. Um @MarcelValdezOrozco zu beantworten, ja, das ist es auch O(n), obwohl es pro 16-Byte-Chunks kopiert, um die Geschwindigkeit zu verbessern (es wird kein Straight memcpyfür die Gesamtlänge verwendet).
Abel
2

Wenn Sie eine Zeichenfolge haben, die nur ASCII-Zeichen enthält, können Sie diese Methode verwenden.

    public static string ASCIIReverse(string s)
    {
        byte[] reversed = new byte[s.Length];

        int k = 0;
        for (int i = s.Length - 1; i >= 0; i--)
        {
            reversed[k++] = (byte)s[i];
        }

        return Encoding.ASCII.GetString(reversed);
    }
Raz Megrelidze
quelle
2

Zuallererst müssen Sie verstehen, dass str + = die Größe Ihres String-Speichers ändert, um Platz für 1 zusätzliches Zeichen zu schaffen. Dies ist in Ordnung, aber wenn Sie beispielsweise ein Buch mit 1000 Seiten haben, das Sie umkehren möchten, dauert die Ausführung sehr lange.

Die Lösung, die einige Leute vorschlagen könnten, ist die Verwendung von StringBuilder. Wenn Sie ein + = ausführen, weist der String Builder viel größere Speicherbereiche zu, um das neue Zeichen aufzunehmen, sodass nicht jedes Mal, wenn Sie ein Zeichen hinzufügen, eine Neuzuweisung vorgenommen werden muss.

Wenn Sie wirklich eine schnelle und minimale Lösung wünschen, würde ich Folgendes vorschlagen:

            char[] chars = new char[str.Length];
            for (int i = str.Length - 1, j = 0; i >= 0; --i, ++j)
            {
                chars[j] = str[i];
            }
            str = new String(chars);

In dieser Lösung gibt es eine anfängliche Speicherzuordnung, wenn char [] initialisiert wird, und eine Zuweisung, wenn der Zeichenfolgenkonstruktor die Zeichenfolge aus dem char-Array erstellt.

Auf meinem System habe ich einen Test für Sie durchgeführt, der eine Zeichenfolge von 2 750 000 Zeichen umkehrt. Hier sind die Ergebnisse für 10 Hinrichtungen:

StringBuilder: 190K - 200K Ticks

Char Array: 130K - 160K Ticks

Ich habe auch einen Test für den normalen String + = durchgeführt, ihn aber nach 10 Minuten ohne Ausgabe abgebrochen.

Ich habe jedoch auch festgestellt, dass der StringBuilder für kleinere Zeichenfolgen schneller ist, sodass Sie sich anhand der Eingabe für die Implementierung entscheiden müssen.

Prost

Reasurria
quelle
funktioniert nicht für😀Les Misérables
Charles
@ Charles Ah ja, es gibt die Zeichensatzbegrenzung, nehme ich an.
Reasurria
2
public static string reverse(string s) 
{
    string r = "";
    for (int i = s.Length; i > 0; i--) r += s[i - 1];
    return r;
}
ddagsan
quelle
1
public static string Reverse2(string x)
        {
            char[] charArray = new char[x.Length];
            int len = x.Length - 1;
            for (int i = 0; i <= len; i++)
                charArray[i] = x[len - i];
            return new string(charArray);
        }
Shrini
quelle