Je viens d'avoir à écrire une fonction de chaîne inversée en C # 2.0 (c'est-à-dire LINQ non disponible) et j'ai trouvé ceci:
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;
}
Personnellement, je ne suis pas fou de la fonction et je suis convaincu qu'il existe une meilleure façon de le faire. Y a-t-il?
Réponses:
la source
Voici une solution qui inverse correctement la chaîne
"Les Mise\u0301rables"
comme"selbare\u0301siM seL"
. Cela devrait être rendu commeselbarésiM seL
, nonselbaŕesiM seL
(notez la position de l'accent), comme le ferait la plupart des implémentations basées sur des unités de code (Array.Reverse
, etc.) ou même des points de code (inversant avec une attention particulière pour les paires de substitution).(Et exemple de course en direct ici: https://ideone.com/DqAeMJ )
Il utilise simplement l' API .NET pour l'itération des grappes de graphèmes , qui existe depuis toujours, mais qui semble un peu "cachée".
la source
Cela s'avère être une question étonnamment délicate.
Je recommanderais d'utiliser Array.Reverse pour la plupart des cas car il est codé en mode natif et il est très simple à maintenir et à comprendre.
Il semble surpasser StringBuilder dans tous les cas que j'ai testés.
Il existe une deuxième approche qui peut être plus rapide pour certaines longueurs de chaîne qui utilise Xor .
Remarque Si vous souhaitez prendre en charge le jeu de caractères complet Unicode UTF16, lisez ceci . Et utilisez plutôt l'implémentation là-bas. Il peut être encore optimisé en utilisant l'un des algorithmes ci-dessus et en parcourant la chaîne pour la nettoyer une fois les caractères inversés.
Voici une comparaison des performances entre la méthode StringBuilder, Array.Reverse et Xor.
Voici les résultats:
Il semble que Xor peut être plus rapide pour les chaînes courtes.
la source
Si vous pouvez utiliser LINQ (.NET Framework 3.5+), suivre un liner vous donnera un code court. N'oubliez pas d'ajouter
using System.Linq;
pour avoir accès àEnumerable.Reverse
:Remarques:
la source
Si la chaîne contient des données Unicode (à proprement parler, des caractères non BMP), les autres méthodes qui ont été publiées le corrompent, car vous ne pouvez pas permuter l'ordre des unités de code de substitution hautes et basses lors de l'inversion de la chaîne. (Vous trouverez plus d'informations à ce sujet sur mon blog .)
L'exemple de code suivant inversera correctement une chaîne qui contient des caractères non BMP, par exemple, "\ U00010380 \ U00010381" (Ugaritic Letter Alpa, Ugaritic Letter Beta).
la source
Ok, dans l'intérêt de "ne vous répétez pas", je vous propose la solution suivante:
Ma compréhension est que cette implémentation, disponible par défaut dans VB.NET, gère correctement les caractères Unicode.
la source
Greg Beech a publié une
unsafe
option qui est en effet aussi rapide que possible (c'est une inversion sur place); mais, comme il l'a indiqué dans sa réponse, c'est une idée complètement désastreuse .Cela dit, je suis surpris qu'il y ait autant de consensus qui
Array.Reverse
soit la méthode la plus rapide. Il existe toujours uneunsafe
approche qui renvoie une copie inversée d'une chaîne (pas de manigances d'inversion sur place) beaucoup plus rapidement que laArray.Reverse
méthode pour les petites chaînes:Voici quelques résultats de référence .
Vous pouvez voir que le gain de performances diminue, puis disparaît par rapport à la
Array.Reverse
méthode à mesure que les chaînes deviennent plus grandes. Pour les cordes petites à moyennes, cependant, il est difficile de battre cette méthode.la source
La réponse facile et agréable utilise la méthode d'extension:
et voici la sortie:
la source
Reverse()
etToArray()
sont dans le mauvais ordre dans votre exemple de code.Si vous voulez jouer à un jeu vraiment dangereux, c'est de loin le moyen le plus rapide qui soit (environ quatre fois plus rapide que la
Array.Reverse
méthode). C'est une marche arrière en place à l'aide de pointeurs.Notez que je ne recommande vraiment jamais cela pour toute utilisation ( jetez un œil ici pour certaines raisons pour lesquelles vous ne devriez pas utiliser cette méthode ), mais il est juste intéressant de voir que cela peut être fait et que les chaînes ne sont pas vraiment immuables une fois que vous activez le code dangereux.
la source
unsafe
code qui n'est pas mauvais et bat toujoursArray.Reverse
dans de nombreux cas. Jetez un oeil à ma réponse.Jetez un œil à l'entrée wikipedia ici . Ils implémentent la méthode d'extension String.Reverse. Cela vous permet d'écrire du code comme ceci:
Ils utilisent également la combinaison ToCharArray / Reverse suggérée par d'autres réponses à cette question. Le code source ressemble à ceci:
la source
Tout d'abord, vous n'avez pas besoin d'appeler
ToCharArray
car une chaîne peut déjà être indexée en tant que tableau de caractères, donc cela vous fera économiser une allocation.L'optimisation suivante consiste à utiliser un
StringBuilder
pour éviter les allocations inutiles (car les chaînes sont immuables, leur concaténation fait une copie de la chaîne à chaque fois). Pour optimiser davantage cela, nous avons prédéfini la longueur du fichierStringBuilder
afin qu'il n'ait pas besoin d'étendre son tampon.Modifier: données de performance
J'ai testé cette fonction et la fonction à l'aide
Array.Reverse
du programme simple suivant, où seReverse1
trouve une fonction etReverse2
l'autre:Il s'avère que pour les chaînes courtes, la
Array.Reverse
méthode est environ deux fois plus rapide que celle ci-dessus, et pour les chaînes plus longues, la différence est encore plus prononcée. Donc, étant donné que laArray.Reverse
méthode est à la fois plus simple et plus rapide, je vous recommande de l'utiliser plutôt que celle-ci. Je laisse celui-ci ici juste pour montrer que ce n'est pas la façon dont vous devriez le faire (à ma grande surprise!)la source
Essayez d'utiliser Array.
la source
Bien sûr, vous pouvez étendre la classe de chaîne avec la méthode Reverse
la source
Enumerable.Reverse(input)
est égal àinput.Reverse()
"Best" peut dépendre de beaucoup de choses, mais voici quelques alternatives plus courtes ordonnées de rapide à lent:
la source
À partir de .NET Core 2.1, il existe une nouvelle façon d'inverser une chaîne à l'aide de la
string.Create
méthode.Notez que cette solution ne gère pas correctement les caractères Unicode combinant etc., car "Les Mise \ u0301rables" serait converti en "selbarésiM seL". Les autres réponses pour une meilleure solution.
Cela copie essentiellement les caractères de
input
dans une nouvelle chaîne et inverse la nouvelle chaîne en place.Pourquoi est
string.Create
utile?Lorsque nous créons une chaîne à partir d'un tableau existant, un nouveau tableau interne est alloué et les valeurs sont copiées. Sinon, il serait possible de muter une chaîne après sa création (dans un environnement sûr). Autrement dit, dans l'extrait de code suivant, nous devons allouer un tableau de longueur 10 deux fois, un comme tampon et un comme tableau interne de la chaîne.
string.Create
nous permet essentiellement de manipuler le tableau interne lors de la création de la chaîne. Autrement dit, nous n'avons plus besoin d'un tampon et pouvons donc éviter d'allouer ce tableau de caractères.Steve Gordon a écrit à ce sujet plus en détail ici . Il y a aussi un article sur MSDN .
Comment utiliser
string.Create
?La méthode prend trois paramètres:
char
tableau interne de la nouvelle chaîne et le second est les données (état) que vous avez transmisesstring.Create
.À l'intérieur du délégué, nous pouvons spécifier comment la nouvelle chaîne est créée à partir des données. Dans notre cas, nous copions simplement les caractères de la chaîne d'entrée dans ceux
Span
utilisés par la nouvelle chaîne. Ensuite, nous inversons leSpan
et donc la chaîne entière est inversée.Repères
Pour comparer ma façon proposée d'inverser une chaîne avec la réponse acceptée, j'ai écrit deux repères en utilisant BenchmarkDotNet.
Voici les résultats sur ma machine:
Comme vous pouvez le voir, avec
ReverseWithStringCreate
nous n'allouons que la moitié de la mémoire utilisée par laReverseWithArray
méthode.la source
Ne vous embêtez pas avec une fonction, faites-le simplement en place. Remarque: La deuxième ligne générera une exception d'argument dans la fenêtre Exécution de certaines versions de VS.
la source
new string
Désolé pour le long post, mais cela pourrait être intéressant
Résultats:
la source
Production
Pour taille: 10
Pour taille: 100
Pour taille: 1000
Pour taille: 10000
la source
Reverse(...)
. Sinon, bon travail.Manière la plus simple:
la source
Solution basée sur la pile.
Ou
la source
Dû soumettre un exemple récursif:
la source
Que diriez-vous:
la source
ToCharArray
première. L'énumérateur LINQ est également beaucoup plus lent queArray.Reverse()
.J'ai créé un port C # à partir de Microsoft.VisualBasic.Strings . Je ne sais pas pourquoi ils gardent ces fonctions utiles (de VB) en dehors de System.String dans Framework, mais toujours sous Microsoft.VisualBasic. Même scénario pour les fonctions financières (par exemple
Microsoft.VisualBasic.Financial.Pmt()
).la source
string s = "abo\u0327\u0307\u035d\U0001d166cd"
, qui contient la lettreo
suivie de 3 combinaisons de signes diacritiques dans le BMP et une marque de combinaison (MUSICAL SYMBOL COMBINING STEM) du plan astral (non-BMP) et il les garde intacts. Mais la méthode est lente si ces caractères n'apparaissent qu'à la fin d'une longue chaîne, car elle doit parcourir deux fois l'ensemble du tableau.Désolé de poster sur ce vieux fil. Je pratique du code pour une interview.
C'est ce que j'ai proposé pour C #. Ma première version avant refactoring était horrible.
Contrairement à la
Array.Reverse
méthode ci-dessous, il apparaît plus rapidement avec 12 caractères ou moins dans la chaîne. Après 13 personnages, leArray.Reverse
commence à s'accélérer, et il finit par dominer assez fortement sur la vitesse. Je voulais juste indiquer approximativement où la vitesse commence à changer.À 100 caractères dans la chaîne, c'est plus rapide que ma version x 4. Cependant, si je savais que les chaînes auraient toujours moins de 13 caractères, j'utiliserais celle que j'ai faite.
Les tests ont été effectués avec
Stopwatch
et 5000000 itérations. De plus, je ne sais pas si ma version gère les substituts ou les situations de caractères combinées avec l'Unicode
encodage.la source
"Meilleure façon" dépend de ce qui est le plus important pour vous dans votre situation, performance, élégance, maintenabilité, etc.
Quoi qu'il en soit, voici une approche utilisant Array.
la source
Si cela est arrivé dans une interview et qu'on vous a dit que vous ne pouviez pas utiliser Array, l'inverse, je pense que cela pourrait être l'un des plus rapides. Il ne crée pas de nouvelles chaînes et itère seulement plus de la moitié du tableau (c'est-à-dire O (n / 2) itérations)
la source
x
, ou dans votre casn
, n'est pas utilisé. Votre algorithme a des performancesf(x) = x + ½x + C
, où C est une constante. Puisque les deuxC
et le facteur1½
ne dépendent pasx
, votre algorithme l'estO(x)
. Cela ne signifie pas qu'il ne sera pas plus rapide pour toute entrée de longueurx
, mais ses performances dépendent linéairement de la longueur d'entrée. Pour répondre à @MarcelValdezOrozco, oui, il l'est aussiO(n)
, bien qu'il copie par morceaux de 16 octets pour améliorer la vitesse (il n'utilise pas de ligne droitememcpy
sur la longueur totale).Si vous avez une chaîne qui ne contient que des caractères ASCII, vous pouvez utiliser cette méthode.
la source
Tout d'abord, ce que vous devez comprendre, c'est que str + = redimensionnera la mémoire de votre chaîne pour faire de la place pour 1 caractère supplémentaire. C'est très bien, mais si vous avez, disons, un livre de 1000 pages que vous souhaitez inverser, cela prendra très longtemps à exécuter.
La solution que certaines personnes pourraient suggérer est d'utiliser StringBuilder. Ce que fait le générateur de chaînes lorsque vous effectuez un + =, c'est qu'il alloue des morceaux de mémoire beaucoup plus grands pour contenir le nouveau caractère de sorte qu'il n'a pas besoin de faire une réallocation chaque fois que vous ajoutez un caractère.
Si vous voulez vraiment une solution rapide et minimale, je vous suggère ce qui suit:
Dans cette solution, il y a une allocation de mémoire initiale lorsque le char [] est initialisé et une allocation lorsque le constructeur de chaîne crée la chaîne à partir du tableau de char.
Sur mon système, j'ai effectué un test pour vous qui inverse une chaîne de 2 750 000 caractères. Voici les résultats de 10 exécutions:
StringBuilder: 190K - 200K ticks
Tableau des chars: 130K - 160K ticks
J'ai également exécuté un test pour String + = normal, mais je l'ai abandonné après 10 minutes sans sortie.
Cependant, j'ai également remarqué que pour les petites chaînes, StringBuilder est plus rapide, vous devrez donc décider de l'implémentation en fonction de l'entrée.
À votre santé
la source
😀Les Misérables
la source
la source