À 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.
public static string Reverse(string input)
{
return string.Create<string>(input.Length, input, (chars, state) =>
{
state.AsSpan().CopyTo(chars);
chars.Reverse();
});
}
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.
var chars = new char[10];
// set array values
var str = new string(chars);
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
?
public static string Create<TState>(int length, TState state, SpanAction<char, TState> action);
La méthode prend trois paramètres:
- La longueur de la chaîne à créer,
- les données que vous souhaitez utiliser pour créer dynamiquement la nouvelle chaîne,
- et un délégué qui crée la chaîne finale à partir des données, où le premier paramètre pointe vers le
char
tableau interne de la nouvelle chaîne et le second est les données (état) que vous avez transmises string.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 le Span
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.
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);
}
Voici les résultats sur ma machine:
| 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 |
Comme vous pouvez le voir, avec ReverseWithStringCreate
nous n'allouons que la moitié de la mémoire utilisée par la ReverseWithArray
méthode.