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?
Antworten:
quelle
Hier eine Lösung, die den String richtig umkehrt
"Les Mise\u0301rables"
als"selbare\u0301siM seL"
. Dies sollte genauso wiedergegeben werdenselbarésiM seL
, nichtselbaŕesiM seL
(beachten Sie die Position des Akzents), wie dies bei den meisten Implementierungen der Fall wäre, die auf Codeeinheiten (Array.Reverse
usw.) oder sogar Codepunkten basieren (Umkehrung mit besonderer Sorgfalt für Ersatzpaare).(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.
quelle
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.
Es gibt einen zweiten Ansatz, der für bestimmte Zeichenfolgenlängen mit Xor schneller sein kann .
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.
Hier sind die Ergebnisse:
Es scheint, dass Xor für kurze Saiten schneller sein kann.
quelle
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 aufEnumerable.Reverse
:Anmerkungen:
quelle
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).
quelle
Ok, im Interesse von "Wiederhole dich nicht" biete ich die folgende Lösung an:
Nach meinem Verständnis verarbeitet diese Implementierung, die standardmäßig in VB.NET verfügbar ist, Unicode-Zeichen ordnungsgemäß.
quelle
Greg Beech hat eine
unsafe
Option 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.Reverse
die schnellste Methode ist. Es gibt immer noch einenunsafe
Ansatz, der eine umgekehrte Kopie eines Strings (keine direkten Umkehrshenanigans) signifikant schnellerArray.Reverse
zurückgibt als die Methode für kleine Strings:Hier sind einige Benchmark-Ergebnisse .
Sie können sehen, dass der Leistungsgewinn abnimmt und dann gegenüber der
Array.Reverse
Methode verschwindet , wenn die Zeichenfolgen größer werden. Bei kleinen bis mittelgroßen Saiten ist diese Methode jedoch schwer zu übertreffen.quelle
Die einfache und nette Antwort ist die Verwendung der Erweiterungsmethode:
und hier ist die Ausgabe:
quelle
Reverse()
undToArray()
sind in der falschen Reihenfolge in Ihrem Codebeispiel.Wenn Sie ein wirklich gefährliches Spiel spielen möchten, ist dies bei weitem der schnellste Weg (ungefähr viermal schneller als die
Array.Reverse
Methode). 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.
quelle
unsafe
Code umzukehren , der nicht böse ist und in vielen Fällen immer noch schlägtArray.Reverse
. Schauen Sie sich meine Antwort an.Schauen Sie sich hier den Wikipedia-Eintrag an . Sie implementieren die Erweiterungsmethode String.Reverse. Auf diese Weise können Sie Code wie folgt schreiben:
Sie verwenden auch die Kombination ToCharArray / Reverse, die andere Antworten auf diese Frage vorschlagen. Der Quellcode sieht folgendermaßen aus:
quelle
Erstens müssen Sie nicht aufrufen,
ToCharArray
da eine Zeichenfolge bereits als Zeichenarray indiziert werden kann, sodass Sie eine Zuordnung sparen.Die nächste Optimierung besteht darin, a
StringBuilder
zu 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 derStringBuilder
Puffer nicht erweitert werden muss.Bearbeiten: Leistungsdaten
Ich habe diese Funktion und die Funktion
Array.Reverse
mit dem folgenden einfachen Programm getestet , wobeiReverse1
eine Funktion undReverse2
die andere ist:Es stellt sich heraus, dass die
Array.Reverse
Methode 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 dieArray.Reverse
Methode 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!)quelle
Versuchen Sie es mit Array.Reverse
quelle
Natürlich können Sie die Zeichenfolgenklasse mit der Reverse-Methode erweitern
quelle
Enumerable.Reverse(input)
ist gleichinput.Reverse()
"Best" kann von vielen Dingen abhängen, aber hier sind einige weitere kurze Alternativen, die von schnell bis langsam geordnet sind:
quelle
Ab .NET Core 2.1 gibt es eine neue Möglichkeit, eine Zeichenfolge mithilfe der
string.Create
Methode 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.
Dies kopiert im Wesentlichen die Zeichen von
input
in eine neue Zeichenfolge und kehrt die neue Zeichenfolge an Ort und Stelle um.Warum ist
string.Create
nü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.
string.Create
Im 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
?Die Methode akzeptiert drei Parameter:
char
Array der neuen Zeichenfolge verweist und der zweite die Daten (Status) ist, an die Sie übergeben habenstring.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
Span
von der neuen Zeichenfolge verwendete. Dann kehren wir das umSpan
und 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.
Hier sind die Ergebnisse auf meiner Maschine:
Wie Sie sehen können,
ReverseWithStringCreate
weisen wir nur die Hälfte des von derReverseWithArray
Methode verwendeten Speichers zu .quelle
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.
quelle
new string
Entschuldigung für den langen Beitrag, aber das könnte interessant sein
Ergebnisse:
quelle
Ausgabe
Für Größe: 10
Für Größe: 100
Für Größe: 1000
Für Größe: 10000
quelle
Reverse(...)
. Ansonsten gute Arbeit.Einfachster Weg:
quelle
Stapelbasierte Lösung.
Oder
quelle
Musste ein rekursives Beispiel einreichen:
quelle
Wie wäre es mit:
quelle
ToCharArray
ersten. Der LINQ-Enumerator ist auch viel langsamer alsArray.Reverse()
.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. ).quelle
string s = "abo\u0327\u0307\u035d\U0001d166cd"
, der den Buchstaben enthält,o
gefolgt 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.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.
Im Gegensatz zur folgenden
Array.Reverse
Methode wird es mit maximal 12 Zeichen in der Zeichenfolge schneller angezeigt. Nach 13 Zeichen wird dasArray.Reverse
schneller und es dominiert schließlich ziemlich stark die Geschwindigkeit. Ich wollte nur ungefähr darauf hinweisen, wo sich die Geschwindigkeit zu ändern beginnt.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
Stopwatch
und 5000000 Iterationen durchgeführt. Ich bin mir auch nicht sicher, ob meine Version Ersatzsituationen oder kombinierte Zeichensituationen mitUnicode
Codierung behandelt.quelle
"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:
quelle
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).
quelle
x
oder in Ihrem Fall abhängign
ist, nicht verwendet. Ihr Algorithmus hat eine Leistungf(x) = x + ½x + C
, wobei C eine Konstante ist. Da beideC
und der Faktor1½
nicht abhängig sindx
, ist Ihr AlgorithmusO(x)
. Das bedeutet nicht, dass es für eine Eingabe der Länge nicht schneller istx
, aber seine Leistung hängt linear von der Eingabelänge ab. Um @MarcelValdezOrozco zu beantworten, ja, das ist es auchO(n)
, obwohl es pro 16-Byte-Chunks kopiert, um die Geschwindigkeit zu verbessern (es wird kein Straightmemcpy
für die Gesamtlänge verwendet).Wenn Sie eine Zeichenfolge haben, die nur ASCII-Zeichen enthält, können Sie diese Methode verwenden.
quelle
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:
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
quelle
😀Les Misérables
quelle
quelle