Лучший способ перевернуть строку

Мне только что пришлось написать функцию 9X_c# обратного преобразования строки в C# 2.0 9X_dot-net (т.е. LINQ недоступен), и я придумал следующее:

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;
}

Лично 9X_dot-net я не без ума от этой функции и убежден, что 9X_csharp есть способ сделать это лучше. Есть?

548
3

  • Гораздо более новая связанная тема: [Перевернуть с ...
39
Общее количество ответов: 39

Ответ #1

Ответ на вопрос: Лучший способ перевернуть строку

public static string Reverse( string s )
{
    char[] charArray = s.ToCharArray();
    Array.Reverse( charArray );
    return new string( charArray );
}

9X_visual-c#

773
8

  • sambo99: не нужно упоминать Unicode: символы в C# - это символы Unicode, а не байты. X ...

Ответ #2

Ответ на вопрос: Лучший способ перевернуть строку

Вот решение, которое правильно меняет строку 9X_performance "Les Mise\u0301rables" на "selbare\u0301siM seL". Он должен отображаться так же, как 9X_algorithm selbarésiM seL, а не selbaŕesiM seL (обратите внимание на положение 9X_fast акцента), как результат большинства реализаций, основанных 9X_unicode на кодовых единицах (Array.Reverse и т. Д.) Или даже 9X_c#.net кодовых точках (обращая особое внимание 9X_.net-framework на суррогатные пары).

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

public static class Test
{
    private static IEnumerable 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);
    }
}

(И живой пример работы 9X_c#.net здесь: https://ideone.com/DqAeMJ)

Он просто использует .NET API for grapheme cluster iteration, который 9X_efficiency существует с тех пор, но, кажется, немного 9X_c#.net «скрыт» от просмотра.

214
4

  • +1 Один из очень немногих правильных ответов, и ** намного ** более элегантный и персп ...

Ответ #3

Ответ на вопрос: Лучший способ перевернуть строку

Это оказался на удивление сложным вопросом.

Я 9X_algorithms бы порекомендовал использовать Array.Reverse 9X_c#.net в большинстве случаев, так как он изначально 9X_.net-framework написан и очень прост в обслуживании и понимании.

Похоже, что 9X_efficiency он превосходит StringBuilder во всех тестируемых 9X_dot-net мной случаях.

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

Есть второй подход, который 9X_c#.net может быть быстрее для строк определенной 9X_unicode длины, например uses Xor.

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

Примечание. Если вы хотите поддерживать 9X_fast полную кодировку Unicode UTF16 read this. И используйте 9X_slow вместо этого реализацию. Его можно дополнительно 9X_dot-net оптимизировать, используя один из описанных 9X_efficiency выше алгоритмов и просматривая строку, чтобы 9X_c#.net очистить ее после того, как символы поменялись 9X_c-sharp местами.

Вот сравнение производительности 9X_slow методов StringBuilder, Array.Reverse и Xor.

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

Вот 9X_dot-net результаты:

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.

Похоже, что Xor может быть быстрее 9X_performance для коротких строк.

130
2

  • Эти методы не обрабатывают строки, содержащие символы вне базовой многоязычной плоскости, то есть символы Unicode> = U + 10000, которые представлены двумя символами C#. Я опубликовал ответ, ко ...

Ответ #4

Ответ на вопрос: Лучший способ перевернуть строку

Если вы можете использовать LINQ (.NET Framework 9X_csharp 3.5+), то следующий один лайнер даст вам 9X_algorithm короткий код. Не забудьте добавить using System.Linq;, чтобы 9X_c# получить доступ к Enumerable.Reverse:

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

Примечания:

  • не самая быстрая версия - согласно Martin Niederl в 5,7 раза медленнее, чем самая быстрая версия здесь.
  • этот код, как и многие другие параметры, полностью игнорирует всевозможные многосимвольные комбинации, поэтому ограничьте использование домашними заданиями и строками, которые не содержат такие символы. См. Другой answer в этом вопросе для реализации, которая правильно обрабатывает такие комбинации.

83
1

  • Не самое быстрое решение, но п ...

Ответ #5

Ответ на вопрос: Лучший способ перевернуть строку

Если строка содержит данные Unicode (строго 9X_csharp говоря, символы, отличные от BMP), другие 9X_fast опубликованные методы повредят ее, потому 9X_c# что вы не можете поменять местами высокие 9X_c-sharp и низкие единицы суррогатного кода при реверсировании 9X_algorithm строки. (Более подробную информацию об этом 9X_c-sharp можно найти на my blog.)

В следующем примере кода 9X_c#.net выполняется обратное преобразование строки, содержащей 9X_algorithms символы, отличные от BMP, например "\ U00010380 9X_csharp \ U00010381" (угаритская буква альпа, угаритская 9X_fast буква бета).

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

51
7

  • @Richard: Правила разбиения кластеров графем немного сложнее, чем просто обнаружение объединения кодовых точек; см. документацию по [Границы кластера графемы] (http://www.unicode.org/repor ...

Ответ #6

Ответ на вопрос: Лучший способ перевернуть строку

Хорошо, в интересах «не повторяться» я предлагаю 9X_unicode следующее решение:

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

Насколько я понимаю, эта 9X_slow реализация, доступная по умолчанию в VB.NET, правильно 9X_slow обрабатывает символы Юникода.

27
1

  • Это правильно обрабатывает только суррогатов. Это мешает совмещать метки: http://ideone.com ...

Ответ #7

Ответ на вопрос: Лучший способ перевернуть строку

Взгляните на статью в Википедии here. Они реализуют 9X_algorithm-design метод расширения String.Reverse. Это позволяет 9X_performance писать такой код:

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

Они также используют комбинацию 9X_c-sharp ToCharArray / Reverse, которую предлагают 9X_fast другие ответы на этот вопрос. Исходный код 9X_performance выглядит так:

public static string Reverse(this string input)
{
    char[] chars = input.ToCharArray();
    Array.Reverse(chars);
    return new String(chars);
}

18
0

Ответ #8

Ответ на вопрос: Лучший способ перевернуть строку

Грег Бич опубликовал опцию unsafe, которая действительно 9X_speed работает настолько быстро, насколько это 9X_dotnet возможно (это реверсирование на месте); но, как 9X_csharp он указал в своем ответе, это a completely disastrous idea.

Тем не менее, я 9X_efficiency удивлен, что многие согласны с тем, что 9X_algorithm Array.Reverse - самый быстрый метод. По-прежнему существует 9X_.net подход unsafe, который возвращает перевернутую 9X_algorithms копию строки (без махинаций разворота на 9X_speed месте) значительно быстрее, чем метод Array.Reverse для небольших строк:

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

Here are some benchmark results.

Вы можете видеть, что 9X_speed прирост производительности уменьшается, а 9X_dotnet затем исчезает для метода Array.Reverse по мере того, как 9X_efficiency строки становятся больше. Однако для струн 9X_algorithm-design малого и среднего размера этот метод сложно 9X_dotnet превзойти.

17
1

  • StackOverflow для больших строк.<p>< ...

Ответ #9

Ответ на вопрос: Лучший способ перевернуть строку

Начиная с .NET Core 2.1 появился новый способ 9X_speed перевернуть строку с помощью метода string.Create.

Обратите внимание, что это решение неправильно обрабатывает комбинированные символы Юникода и т. д., поскольку «Les Mise \ u0301rables» будет преобразовано в «selbarésiM seL». the other answers для лучшего решения.

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

По 9X_dot-net сути, это копирует символы input в новую строку 9X_performance и меняет местами новую строку.

Чем полезен string.Create?

Когда мы создаем 9X_efficiency строку из существующего массива, выделяется 9X_c#.net новый внутренний массив и значения копируются. В 9X_speed противном случае можно было бы изменить 9X_.net-framework строку после ее создания (в безопасной среде). То 9X_dotnet есть в следующем фрагменте мы должны дважды 9X_c#.net выделить массив длиной 10: один в качестве 9X_algorithm-design буфера, а другой - в качестве внутреннего 9X_speed массива строки.

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

string.Create по существу позволяет нам 9X_algorithm манипулировать внутренним массивом во время 9X_c# создания строки. То есть нам больше не нужен 9X_performance буфер, и поэтому мы можем избежать выделения 9X_performance этого единственного массива символов.

Стив 9X_c-sharp Гордон написал об этом более подробно here. Также 9X_c-sharp есть статья на MSDN.

Как использовать string.Create?

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

Метод принимает три параметра:

  1. Длина создаваемой строки,
  2. данные, которые вы хотите использовать для динамического создания новой строки,
  3. и делегат, который создает последнюю строку из данных, где первый параметр указывает на внутренний массив char новой строки, а второй - данные (состояние), которые вы передали в string.Create.

Внутри 9X_visual-c# делегата мы можем указать, как новая строка 9X_dotnet создается из данных. В нашем случае мы просто 9X_performance копируем символы входной строки в Span, используемый 9X_.net-framework новой строкой. Затем мы инвертируем Span, и, следовательно, вся 9X_csharp строка переворачивается.

Тесты

Чтобы сравнить предложенный 9X_c# мной способ обращения строки с принятым 9X_algorithms ответом, я написал два теста с использованием 9X_efficiency 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);
}

Вот результаты на моей машине:

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

Как 9X_performance видите, с помощью ReverseWithStringCreate мы выделяем только половину 9X_c#.net памяти, используемой методом ReverseWithArray.

17
0

Ответ #10

Ответ на вопрос: Лучший способ перевернуть строку

Простой и приятный ответ - использовать 9X_visual-c# метод расширения:

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

и вот результат:

string Answer = "12345".Inverse(); // = "54321"

16
1

  • @ user5389726598465 См. эту ссылку: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/tokens/verbatim Поскольку 'base' - это ключевое слово в ...

Ответ #11

Ответ на вопрос: Лучший способ перевернуть строку

Во-первых, вам не нужно вызывать ToCharArray, поскольку 9X_performance строка уже может быть проиндексирована как 9X_.net массив символов, поэтому это сэкономит вам 9X_slow выделение.

Следующая оптимизация заключается 9X_dotnet в использовании StringBuilder для предотвращения ненужных 9X_dotnet выделений (поскольку строки неизменяемы, их 9X_algorithms конкатенация каждый раз создает копию строки). Для 9X_performance дальнейшей оптимизации мы предварительно 9X_algorithm установили длину StringBuilder, чтобы не нужно было расширять 9X_dot-net буфер.

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

Изменить: данные об эффективности

Я протестировал эту функцию и функцию 9X_efficiency с помощью Array.Reverse с помощью следующей простой программы, где 9X_c#.net Reverse1 - одна функция, а Reverse2 - другая:

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

Оказывается, для 9X_performance коротких строк метод Array.Reverse примерно в два раза 9X_.net быстрее, чем приведенный выше, а для более 9X_csharp длинных строк разница еще более заметна. Поэтому, учитывая, что 9X_slow метод Array.Reverse проще и быстрее, я бы рекомендовал 9X_algorithms вам использовать его, а не этот. Я оставляю 9X_visual-c# это здесь, чтобы показать, что вы должны 9X_fast это делать не так (к моему большому удивлению!)

14
0

Ответ #12

Ответ на вопрос: Лучший способ перевернуть строку

Если вы хотите сыграть в действительно опасную 9X_csharp игру, то это, безусловно, самый быстрый 9X_unicode способ (примерно в четыре раза быстрее, чем 9X_.net-framework метод Array.Reverse). Это обратный ход с использованием 9X_algorithm-design указателей.

Обратите внимание, что я действительно 9X_dotnet не рекомендую это для любого использования 9X_c-sharp (have a look here for some reasons why you should not use this method), но просто интересно увидеть, что это 9X_.net-framework можно сделать, и что строки на самом деле 9X_speed не являются неизменяемыми после включения 9X_performance небезопасного кода.

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;
    }
}

14
0

Ответ #13

Ответ на вопрос: Лучший способ перевернуть строку

Попробуйте использовать Array.Reverse


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

9X_c#

11
0

Ответ #14

Ответ на вопрос: Лучший способ перевернуть строку

«Лучшее» может зависеть от многих вещей, но 9X_visual-c# вот еще несколько коротких альтернатив, упорядоченных 9X_c# от быстрого к медленному:

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̽"  👍

11
0

Ответ #15

Ответ на вопрос: Лучший способ перевернуть строку

public static string Reverse(string input)
{
    return string.Concat(Enumerable.Reverse(input));
}

Конечно, вы можете расширить строковый класс 9X_c# с помощью метода Reverse

public static class StringExtensions
{
    public static string Reverse(this string input)
    {
        return string.Concat(Enumerable.Reverse(input));
    }
}
10
0

Ответ #16

Ответ на вопрос: Лучший способ перевернуть строку

Не беспокойтесь о функции, просто сделайте 9X_c# это на месте. Примечание. Вторая строка 9X_.net вызовет исключение аргумента в окне «Немедленное» некоторых 9X_slow версий VS.

string s = "Blah";
s = new string(s.ToCharArray().Reverse().ToArray()); 

7
1

  • Какой-то парень нашел время, чтобы проголосовать против каждого ответа (включая мой), не объяс ...

Ответ #17

Ответ на вопрос: Лучший способ перевернуть строку

Извините за длинный пост, но это может быть 9X_algorithm-design интересно

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 resultStack = new Stack();
            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");            
        }
    }
}

Результаты:

  • ReverseUsingCharacterBuffer: 346 мс
  • ReverseUsingArrayClass: 87 мс
  • ReverseUsingStringBuilder: 824 мс
  • ReverseUsingStack: 2086 мс
  • ReverseUsingXOR: 319 мс

6
0

Ответ #18

Ответ на вопрос: Лучший способ перевернуть строку

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

Вывод

Для размера: 10

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

Для размера: 100

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

Для размера: 1000

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

Для размера: 10000

Naive Ticks: 32
Efficient linear Ticks: 28
Recursive Ticks: 84808
DotNet Reverse Ticks: 33

9X_c#.net

5
1

  • Необходимо проверить пустую строку в `Revers ...

Ответ #19

Ответ на вопрос: Лучший способ перевернуть строку

Самый простой способ:

string reversed = new string(text.Reverse().ToArray());

9X_.net-framework

5
0

Ответ #20

Ответ на вопрос: Лучший способ перевернуть строку

Решение на основе стека

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

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

        return new string(array);
    }

Или

    public static string Reverse(string text)
    {
        var stack = new Stack(text);
        return string.Join("", stack);
    }

9X_algorithm

4
0

Ответ #21

Ответ на вопрос: Лучший способ перевернуть строку

Пришлось представить рекурсивный пример:

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

9X_algorithm

3
1

  • строка длины 0 ...

Ответ #22

Ответ на вопрос: Лучший способ перевернуть строку

Как насчет

    private string Reverse(string stringToReverse)
    {
        char[] rev = stringToReverse.Reverse().ToArray();
        return new string(rev); 
    }

9X_c-sharp

3
0

Ответ #23

Ответ на вопрос: Лучший способ перевернуть строку

Я сделал порт C# из Microsoft.VisualBasic.Strings. Я не уверен, почему 9X_dot-net они хранят такие полезные функции (из VB) вне 9X_dot-net System.String в Framework, но по-прежнему 9X_algorithm в Microsoft.VisualBasic. Тот же сценарий 9X_fast для финансовых функций (например, Microsoft.VisualBasic.Financial.Pmt()).

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

///This routine handles reversing Strings containing graphemes
/// GRAPHEME: a text element that is displayed as a single character
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();
}

3
0

Ответ #24

Ответ на вопрос: Лучший способ перевернуть строку

Приносим извинения за сообщение в этой старой 9X_speed беседе. Я отрабатываю код для собеседования.

Это 9X_algorithm то, что я придумал для C#. Моя первая версия 9X_dotnet до рефакторинга была ужасной.

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

В отличие от 9X_slow метода Array.Reverse ниже, он отображается быстрее, если 9X_c#.net в строке не более 12 символов. После 13 9X_.net символов Array.Reverse начинает ускоряться, и в конечном 9X_dotnet итоге он довольно сильно влияет на скорость. Я 9X_unicode просто хотел примерно указать, где скорость 9X_speed начинает меняться.

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

    Array.Reverse(charA);

    return new String(charA);
}

При 100 символах в строке 9X_dot-net это быстрее, чем в моей версии x 4. Однако, если 9X_speed бы я знал, что строки всегда будут меньше 9X_c#.net 13 символов, я бы использовал тот, который 9X_csharp я сделал.

Тестирование проводилось с использованием 9X_dot-net Stopwatch и 5000000 итераций. Кроме того, я не уверен, обрабатывает 9X_dotnet ли моя версия суррогаты или комбинированные 9X_fast символьные ситуации с кодировкой Unicode.

3
0

Ответ #25

Ответ на вопрос: Лучший способ перевернуть строку

Поскольку мне нравится пара ответов - один 9X_dotnet для использования string.Create и, следовательно, высокой 9X_csharp производительности и низкого распределения, а 9X_algorithm другой для правильности - с использованием 9X_c-sharp класса StringInfo, я решил, что необходим комбинированный 9X_algorithms подход. Это идеальный метод переворота строки 9X_dot-net :)

private static string ReverseString(string str)
    {
        return string.Create(str.Length, str, (chars, state) =>
        {
            var enumerator = StringInfo.GetTextElementEnumerator(state);
            var position = state.Length;
            while (enumerator.MoveNext())
            {
                var cluster = ((string)enumerator.Current).AsSpan();
                cluster.CopyTo(chars.Slice(position - cluster.Length));
                position -= cluster.Length;
            }
        });
    }

Есть еще лучший способ использовать метод 9X_fast класса StringInfo, который пропускает большое 9X_performance количество выделенных строк перечислителем, возвращая 9X_fast только индексы.

private static string ReverseString(string str)
    {
        return string.Create(str.Length, str, (chars, state) =>
        {
            var position = 0;
            var indexes = StringInfo.ParseCombiningCharacters(state); // skips string creation
            var stateSpan = state.AsSpan();
            for (int len = indexes.Length, i = len - 1; i >= 0; i--)
            {
                var index = indexes[i];
                var spanLength = i == len - 1 ? state.Length - index : indexes[i + 1] - index;
                stateSpan.Slice(index, spanLength).CopyTo(chars.Slice(position));
                position += spanLength;
            }
        });
    }

Некоторые тесты по сравнению 9X_c-sharp с решением LINQ:

String length 20:

LINQ                       Mean: 2,355.5 ns   Allocated: 1440 B
string.Create              Mean:   851.0 ns   Allocated:  720 B
string.Create with indexes Mean:   466.4 ns   Allocated:  168 B

String length 450:

LINQ                          Mean: 34.33 us   Allocated: 22.98 KB
string.Create                 Mean:   19.13 us   Allocated: 14.98 KB
string.Create with indexes    Mean:   10.32 us   Allocated: 2.69 KB

3
0

Ответ #26

Ответ на вопрос: Лучший способ перевернуть строку

«Лучший способ» зависит от того, что для 9X_slow вас важнее в вашей ситуации: производительность, элегантность, ремонтопригодность 9X_c#.net и т. д.

В любом случае, вот подход с использованием 9X_fast 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);

2
0

Ответ #27

Ответ на вопрос: Лучший способ перевернуть строку

Если это когда-нибудь всплывало на собеседовании, и 9X_algorithm-design вам сказали, что вы не можете использовать 9X_algorithm Array.Reverse, я думаю, что это будет одним 9X_algorithm-design из самых быстрых. Он не создает новых строк 9X_visual-c# и выполняет итерацию только по половине 9X_algorithm-design массива (т.е. O (n / 2) итераций)

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

2
1

  • Я почти уверен, что вызов stringToReverse.ToCharArray() приведет к ...

Ответ #28

Ответ на вопрос: Лучший способ перевернуть строку

Если у вас есть строка, содержащая только 9X_fast символы ASCII, вы можете использовать этот 9X_speed метод.

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

2
0

Ответ #29

Ответ на вопрос: Лучший способ перевернуть строку

Прежде всего, вы должны понять, что str 9X_fast + = изменит размер вашей строковой памяти, чтобы 9X_algorithms освободить место для 1 дополнительного символа. Это 9X_c#.net нормально, но если у вас есть, скажем, книга 9X_speed с 1000 страницами, которую вы хотите перевернуть, это 9X_visual-c# займет очень много времени.

Некоторые люди 9X_dot-net могут предложить решение с использованием 9X_algorithm StringBuilder. Что делает построитель строк, когда 9X_speed вы выполняете + =, так это то, что он выделяет 9X_c# гораздо большие блоки памяти для хранения 9X_dotnet нового символа, поэтому ему не нужно делать 9X_.net перераспределение каждый раз, когда вы добавляете 9X_c# char.

Если вам действительно нужно быстрое 9X_speed и минимальное решение, я бы предложил следующее:

            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);

В 9X_algorithm этом решении есть одно начальное выделение 9X_.net памяти при инициализации char [] и одно 9X_dotnet выделение, когда конструктор строки строит 9X_csharp строку из массива char.

В своей системе я 9X_algorithms провел для вас тест, который переворачивает 9X_.net-framework строку из 2 750 000 символов. Вот результаты 9X_csharp 10 казней:

StringBuilder: 190–200 000 тиков

Массив 9X_algorithms символов: 130–160 тыс. тиков

Я также провел 9X_c-sharp тест на нормальный String + =, но отказался 9X_.net-framework от него через 10 минут без каких-либо результатов.

Однако 9X_fast я также заметил, что для меньших строк StringBuilder 9X_fast работает быстрее, поэтому вам придется выбирать 9X_algorithm-design реализацию на основе ввода.

Ура

2
0

Ответ #30

Ответ на вопрос: Лучший способ перевернуть строку

public static string reverse(string s) 
{
    string r = "";
    for (int i = s.Length; i > 0; i--) r += s[i - 1];
    return r;
}

9X_algorithms

2
0

Ответ #31

Ответ на вопрос: Лучший способ перевернуть строку

Если кто-то спросит о реверсе строки, цель 9X_csharp может заключаться в том, чтобы узнать, знаете 9X_c#.net ли вы какие-либо побитовые операции, такие 9X_c#.net как XOR. В C# у вас есть функция Array.Reverse, однако 9X_efficiency вы можете выполнить простую операцию XOR 9X_efficiency в нескольких строках кода (минимально)

    public static string MyReverse(string s)
    {
        char[] charArray = s.ToCharArray();
        int bgn = -1;
        int end = s.Length;
        while(++bgn < --end)
        {
            charArray[bgn] ^= charArray[end];
            charArray[end] ^= charArray[bgn];
            charArray[bgn] ^= charArray[end];
        }
        return new string(charArray);
    }

2
0

Ответ #32

Ответ на вопрос: Лучший способ перевернуть строку

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

9X_visual-c#

1
0

Ответ #33

Ответ на вопрос: Лучший способ перевернуть строку

private static string Reverse(string str)
        {
            string revStr = string.Empty;
            for (int i = str.Length - 1; i >= 0; i--)
            {
                revStr += str[i].ToString();
            }
            return revStr;
        }

Быстрее, чем указано выше

private static string ReverseEx(string str)
        {
            char[] chrArray = str.ToCharArray();
            int len = chrArray.Length - 1;
            char rev = 'n';
            for (int i = 0; i <= len/2; i++)
            {
                rev = chrArray[i];
                chrArray[i] = chrArray[len - i];
                chrArray[len - i] = rev;
            }
            return new string(chrArray);
        }

9X_fast

1
0

Ответ #34

Ответ на вопрос: Лучший способ перевернуть строку

Существуют различные способы перевернуть 9X_slow строку, я показал три из них ниже.

- Использование 9X_fast функции Array.Reverse.

 private static string ReverseString1(string text)
    {
        char[] rtext = text.ToCharArray();
        Array.Reverse(rtext);
        return new string(rtext);
    }

- использовать только 9X_performance строку

  private static string ReverseString2(string text)
    {
        String rtext = "";
        for (int i = text.Length - 1; i >= 0; i--)
        {
            rtext = rtext + text[i];
        }
        return rtext;
    }

- Использование только массива символов

 public static string ReverseString3(string str)
    {
        char[] chars = str.ToCharArray();
        char[] rchars = new char[chars.Length];
        for (int i = 0, j = str.Length - 1; i < chars.Length; i++, j--)
        {
            rchars[j] = chars[i];
        }
        return new string(rchars);
    }

1
0

Ответ #35

Ответ на вопрос: Лучший способ перевернуть строку

Вот так просто:

string x = "your string";       
string x1 = "";
for(int i = x.Length-1 ; i >= 0; i--)
    x1 += x[i];
Console.WriteLine("The reverse of the string is:\n {0}", x1);

См. output.

9X_algorithm-design

1
1

  • Имейте в виду, что, используя этот метод, вы создаете x.Length, умножая на новый объект string, x1, так как вы не принимаете во внимание неизменность ...

Ответ #36

Ответ на вопрос: Лучший способ перевернуть строку

это безопасная для Unicode версия функции, написанная 9X_csharp как расширение, которое будет безопасно 9X_speed обрабатывать Unicode. Он близок к отмеченному 9X_c#.net полному ответу, но не создает исключений 9X_performance для «Недопустимый высокий суррогатный символ».

public static class StringExtensions
{
    public static string Reverse(this string s)
    {
        var info = new StringInfo(s);
        var charArray = new char[s.Length];
        var teIndices = StringInfo.ParseCombiningCharacters(s).Reverse();

        int j = 0;
        foreach(var i in  teIndices)
        {
            if (char.IsHighSurrogate(s[i]))
            {
                charArray[j] = s[i];
                j++;
                charArray[j] = s[i+1];
            }
            else
            {
                charArray[j] = s[i];
            }
            j++;
        }

        return new string(charArray);

    }
}

1
0

Ответ #37

Ответ на вопрос: Лучший способ перевернуть строку

Как насчет использования подстроки

static string ReverseString(string text)
{
    string sub = "";
    int indexCount = text.Length - 1;
    for (int i = indexCount; i > -1; i--)
    {
        sub = sub + text.Substring(i, 1);
    }
    return sub;
}

9X_algorithm

1
1

  • может захотеть изменить его на `sub = sub + text.Substring (i, 1);` и вместо запи ...

Ответ #38

Ответ на вопрос: Лучший способ перевернуть строку

Использование функции агрегирования LINQ

string s = "Karthik U";
s = s.Aggregate(new StringBuilder(), (o, p) => o.Insert(0, p)).ToString();

9X_algorithms

1
1

  • Это очень медленно для ...

Ответ #39

Ответ на вопрос: Лучший способ перевернуть строку

Обрабатывает все типы символов Юникода

с 9X_speed помощью System.Globalization;

    public static string ReverseString(this string content) {

        var textElementEnumerator = StringInfo.GetTextElementEnumerator(content);

        var SbBuilder = new StringBuilder(content.Length);

        while (textElementEnumerator.MoveNext()) {
            SbBuilder.Insert(0, textElementEnumerator.GetTextElement());
        }

        return SbBuilder.ToString();
    }

1
0