Я просто должен был написать функцию обратного преобразования строк в C # 2.0 (т.е. 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;
}
Лично я не без ума от этой функции и уверен, что есть лучший способ сделать это. Есть?
Ответы:
источник
Здесь решение, которое правильно переворачивает строку
"Les Mise\u0301rables"
как"selbare\u0301siM seL"
. Это должно отображаться точно так же, какselbarésiM seL
(неselbaŕesiM seL
отмечать положение акцента), как результат большинства реализаций, основанных на единицах кода (Array.Reverse
и т. Д.) Или даже на точках кода (обращаясь с особой тщательностью к суррогатным парам).(И пример работы в прямом эфире здесь: https://ideone.com/DqAeMJ )
Он просто использует .NET API для итерации кластера графемы , который был там с тех пор, но кажется немного «скрытым» от глаз.
источник
Это оказывается удивительно сложным вопросом.
Я бы порекомендовал использовать Array.Reverse для большинства случаев, так как он изначально кодируется и его очень просто поддерживать и понимать.
Кажется, он превосходит StringBuilder во всех случаях, которые я тестировал.
Существует второй подход, который может быть быстрее для определенных длин строк, который использует Xor .
Примечание. Если вы хотите поддерживать полную кодировку Unicode UTF16, прочтите это . И используйте реализацию там вместо этого. Он может быть дополнительно оптимизирован с помощью одного из вышеперечисленных алгоритмов и выполнения строки, чтобы очистить ее после обращения символов.
Вот сравнение производительности между методами StringBuilder, Array.Reverse и Xor.
Вот результаты:
Кажется, что Xor может быть быстрее для коротких строк.
источник
Если вы можете использовать LINQ (.NET Framework 3.5+), то следуя одному вкладышу, вы получите короткий код. Не забудьте добавить,
using System.Linq;
чтобы иметь доступ кEnumerable.Reverse
:Ноты:
источник
Если строка содержит данные Unicode (строго говоря, не-BMP-символы), другие опубликованные методы повредят ее, потому что вы не можете поменять местами порядковые единицы высокого и низкого суррогатного кода при обращении строки. (Более подробную информацию об этом можно найти в моем блоге .)
Следующий пример кода правильно перевернет строку, содержащую символы, отличные от BMP, например, «\ U00010380 \ U00010381» (Ugaritic Letter Alpa, Ugaritic Letter Beta).
источник
Хорошо, в интересах «не повторяйся» я предлагаю следующее решение:
Насколько я понимаю, эта реализация, доступная по умолчанию в VB.NET, правильно обрабатывает символы Юникода.
источник
Грег Бич (Greg Beech) опубликовал
unsafe
опцию, которая действительно настолько быстра, насколько это возможно (это разворот на месте); но, как он указал в своем ответе, это совершенно катастрофическая идея .Тем не менее, я удивлен, что так много консенсуса, что
Array.Reverse
это самый быстрый метод. Есть ещеunsafe
подход, который возвращает обратную строку (без изменений на месте) значительно быстрее, чемArray.Reverse
метод для маленьких строк:Вот некоторые результаты тестов .
Вы можете видеть, что прирост производительности уменьшается, а затем исчезает по сравнению с
Array.Reverse
методом по мере увеличения строк. Однако для струн малого и среднего размера этот метод трудно обойти.источник
Простой и приятный ответ - использование метода расширения:
и вот вывод:
источник
Reverse()
иToArray()
в неправильном порядке в вашем примере кода.Если вы хотите играть в действительно опасную игру, то это самый быстрый способ (примерно в четыре раза быстрее, чем
Array.Reverse
метод). Это обратный процесс с использованием указателей.Обратите внимание, что я действительно никогда не рекомендую это для какого-либо использования ( посмотрите здесь по некоторым причинам, почему вы не должны использовать этот метод ), но просто интересно посмотреть, что это можно сделать, и что строки на самом деле не являются неизменяемыми как только вы включите небезопасный код.
источник
unsafe
код, который все еще бьет во многих случаях. Посмотрите на мой ответ.Array.Reverse
Посмотрите на запись в Википедии здесь . Они реализуют метод расширения String.Reverse. Это позволяет вам писать код так:
Они также используют комбинацию ToCharArray / Reverse, которую предлагают другие ответы на этот вопрос. Исходный код выглядит так:
источник
Во-первых, вам не нужно вызывать,
ToCharArray
поскольку строку уже можно проиндексировать как массив символов, так что это сэкономит вам место.Следующая оптимизация заключается в использовании a
StringBuilder
для предотвращения ненужных выделений (поскольку строки неизменяемы, их объединение создает копию строки каждый раз). Для дальнейшей оптимизации мы заранее установили длину,StringBuilder
чтобы не нужно было расширять свой буфер.Изменить: данные о производительности
Я протестировал эту функцию и функцию, используя
Array.Reverse
следующую простую программу, гдеReverse1
одна функция, аReverse2
другая:Оказывается, что для коротких строк
Array.Reverse
метод примерно вдвое быстрее, чем приведенный выше, а для более длинных строк разница еще более выражена. Поэтому, учитывая, чтоArray.Reverse
метод является более простым и быстрым, я бы порекомендовал вам использовать его, а не этот. Я оставляю это здесь, чтобы показать, что вы не должны делать это (к моему большому удивлению!)источник
Попробуйте использовать Array.Reverse
источник
Конечно, вы можете расширить класс строки с помощью метода Reverse
источник
Enumerable.Reverse(input)
input.Reverse()
«Лучший» может зависеть от многих вещей, но вот несколько коротких альтернатив, упорядоченных от быстрого к медленному:
источник
Начиная с .NET Core 2.1, появился новый способ обратить строку, используя
string.Create
метод.Обратите внимание, что это решение не обрабатывает Юникод, комбинирующий символы и т. Д. Правильно, поскольку "Les Mise \ u0301rables" будет преобразован в "selbarésiM seL". В другие ответы для лучшего решения.
По сути, это копирует символы
input
в новую строку и переворачивает новую строку на месте.Чем
string.Create
полезен?Когда мы создаем строку из существующего массива, выделяется новый внутренний массив и значения копируются. В противном случае можно было бы изменить строку после ее создания (в безопасной среде). То есть в следующем фрагменте мы должны выделить массив длиной 10 дважды, один в качестве буфера и один в качестве внутреннего массива строки.
string.Create
по сути, позволяет нам манипулировать внутренним массивом во время создания строки. Это значит, что нам больше не нужен буфер, и поэтому мы можем избежать выделения этого одного массива символов.Стив Гордон написал об этом более подробно здесь . Также есть статья на MSDN .
Как использовать
string.Create
?Метод принимает три параметра:
char
массив новой строки, а второй - на данные (состояние), которые вы передалиstring.Create
.Внутри делегата мы можем указать, как новая строка создается из данных. В нашем случае мы просто копируем символы входной строки в
Span
используемую новую строку. Затем мы обращаемSpan
переворачиваем и, следовательно, вся строка переворачивается.Ориентиры
Чтобы сравнить предложенный мной способ обращения строки с принятым ответом, я написал два теста, используя BenchmarkDotNet.
Вот результаты на моей машине:
Как видите, с помощью
ReverseWithStringCreate
мы выделяем только половину памяти, используемойReverseWithArray
методом.источник
Не беспокойтесь о функции, просто сделайте это на месте. Примечание: вторая строка вызовет исключение аргумента в окне Immediate некоторых версий VS.
источник
new string
Извините за длинный пост, но это может быть интересно
Результаты:
источник
Вывод
Для размера: 10
Для размера: 100
Для размера: 1000
Для размера: 10000
источник
Reverse(...)
. В остальном хорошая работа.Самый простой способ:
источник
Стек на основе решения.
Или
источник
Пришлось представить рекурсивный пример:
источник
Как насчет:
источник
ToCharArray
первом. Перечислитель LINQ также намного медленнее, чемArray.Reverse()
.Я сделал порт C # из Microsoft.VisualBasic.Strings . Я не уверен, почему они хранят такие полезные функции (из VB) вне System.String в Framework, но все еще в Microsoft.VisualBasic. Тот же сценарий для финансовых функций (например
Microsoft.VisualBasic.Financial.Pmt()
).источник
string s = "abo\u0327\u0307\u035d\U0001d166cd"
, который содержит букву,o
за которой следуют 3 объединяющих диакритических знака в BMP и один объединяющий знак (МУЗЫКАЛЬНАЯ СИМВОЛНАЯ КОМБИНИРУЮЩАЯ СТЕМА) с астрального плана (не-BMP), и он сохраняет их нетронутыми. Но метод медленный, если такие символы появляются только в конце длинной строки, так как он должен пройти дважды по всему массиву.Извините за публикацию в этой старой теме. Я практикую код для интервью.
Это было то, что я придумал для C #. Моя первая версия до рефакторинга была ужасной.
В отличие от
Array.Reverse
метода, приведенного ниже, он отображается быстрее с 12 или менее символами в строке. После 13 персонажейArray.Reverse
начинает становиться быстрее, и это в конечном итоге довольно сильно доминирует на скорости. Я просто хотел указать приблизительно, где скорость начинает меняться.При 100 символах в строке это быстрее, чем моя версия х 4. Однако, если бы я знал, что строки всегда будут меньше чем 13 символов, я бы использовал тот, который я сделал.
Тестирование было выполнено с
Stopwatch
5000000 итерациями. Кроме того, я не уверен, что моя версия обрабатывает суррогаты или комбинированные ситуации символов сUnicode
кодированием.источник
«Лучший путь» зависит от того, что для вас важнее в вашей ситуации, производительности, элегантности, ремонтопригодности и т. Д.
В любом случае, вот подход с использованием Array.Reverse:
источник
Если это когда-нибудь всплыло в интервью, и вам сказали, что вы не можете использовать Array.Reverse, я думаю, что это может быть одним из самых быстрых. Он не создает новые строки и повторяет только более половины массива (т.е. O (n / 2) итераций)
источник
x
или, в вашем случае,n
не используется. Ваш алгоритм имеет производительностьf(x) = x + ½x + C
, где C - некоторая константа. Поскольку обаC
и фактор1½
не зависят отx
, ваш алгоритмO(x)
. Это не означает, что он не будет быстрее для любого ввода длиныx
, но его производительность линейно зависит от длины ввода. Чтобы ответить на @MarcelValdezOrozco, да, это также такO(n)
, хотя он копирует на 16-байтовые блоки для повышения скорости (он не использует прямоеmemcpy
на общей длине).Если у вас есть строка, содержащая только символы ASCII, вы можете использовать этот метод.
источник
Прежде всего, вы должны понять, что str + = изменит размер вашей строковой памяти, чтобы освободить место для 1 дополнительного символа. Это нормально, но если у вас есть, скажем, книга с 1000 страницами, которую вы хотите перевернуть, это займет очень много времени.
Решение, которое некоторые люди могут предложить, - это использование StringBuilder. Что делает строитель строк, когда вы выполняете + =, так это то, что он выделяет гораздо большие куски памяти для хранения нового символа, так что ему не нужно выполнять перераспределение каждый раз, когда вы добавляете символ.
Если вы действительно хотите быстрое и минимальное решение, я бы предложил следующее:
В этом решении есть одно начальное выделение памяти, когда инициализируется char [], и одно выделение, когда строковый конструктор строит строку из массива char.
В моей системе я провел для вас тест, который переворачивает строку из 2 750 000 символов. Вот результаты для 10 казней:
StringBuilder: 190K - 200K тиков
Char Char Array: 130K - 160K тиков
Я также запустил тест на нормальный тип String + =, но я отказался от него через 10 минут без вывода.
Однако я также заметил, что для небольших строк StringBuilder работает быстрее, поэтому вам придется выбирать реализацию на основе входных данных.
ура
источник
😀Les Misérables
источник
источник