Solo tuve que escribir una función inversa de cadena en C # 2.0 (es decir, LINQ no está disponible) y se me ocurrió esto:
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;
}
Personalmente, no estoy loco por la función y estoy convencido de que hay una mejor manera de hacerlo. ¿Esta ahí?
Respuestas:
fuente
Aquí una solución que invierte correctamente la cadena
"Les Mise\u0301rables"
como"selbare\u0301siM seL"
. Esto debería ser igual queselbarésiM seL
noselbaŕesiM seL
(tenga en cuenta la posición del acento), como sería el resultado de la mayoría de las implementaciones basadas en unidades de código (Array.Reverse
, etc.) o incluso puntos de código (invirtiendo con especial cuidado para los pares sustitutos).(Y ejemplo en vivo aquí: https://ideone.com/DqAeMJ )
Simplemente usa la API .NET para la iteración del clúster de grafemas , que ha estado allí desde siempre, pero parece un poco "oculto" a la vista.
fuente
Esta es una pregunta sorprendentemente complicada.
Recomendaría usar Array.Reverse para la mayoría de los casos, ya que está codificado de forma nativa y es muy sencillo de mantener y comprender.
Parece superar a StringBuilder en todos los casos que probé.
Hay un segundo enfoque que puede ser más rápido para ciertas longitudes de cadena que usa Xor .
Nota: si desea admitir el juego de caracteres Unicode UTF16 completo, lea esto . Y use la implementación allí en su lugar. Se puede optimizar aún más utilizando uno de los algoritmos anteriores y ejecutando la cadena para limpiarlo después de invertir los caracteres.
Aquí hay una comparación de rendimiento entre el método StringBuilder, Array.Reverse y Xor.
Aquí están los resultados:
Parece que Xor puede ser más rápido para cadenas cortas.
fuente
Si puede usar LINQ (.NET Framework 3.5+), el siguiente código le dará un código breve. No olvides agregar
using System.Linq;
para tener acceso aEnumerable.Reverse
:Notas:
fuente
Si la cadena contiene datos Unicode (estrictamente hablando, caracteres que no son BMP), los otros métodos que se han publicado la corromperán, porque no puede intercambiar el orden de las unidades de código sustituto alto y bajo al invertir la cadena. (Puede encontrar más información sobre esto en mi blog ).
El siguiente ejemplo de código invertirá correctamente una cadena que contiene caracteres que no son BMP, por ejemplo, "\ U00010380 \ U00010381" (letra ugarítica Alpa, letra ugarítica Beta).
fuente
Ok, en aras de "no te repitas", ofrezco la siguiente solución:
Tengo entendido que esta implementación, disponible de forma predeterminada en VB.NET, maneja correctamente los caracteres Unicode.
fuente
Greg Beech publicó una
unsafe
opción que de hecho es lo más rápida posible (es una inversión en el lugar); pero, como indicó en su respuesta, es una idea completamente desastrosa .Dicho esto, me sorprende que haya tanto consenso que
Array.Reverse
es el método más rápido. Todavía hay ununsafe
enfoque que devuelve una copia invertida de una cadena (sin travesuras de inversión en el lugar) significativamente más rápido que elArray.Reverse
método para cadenas pequeñas:Aquí hay algunos resultados de referencia .
Puede ver que la ganancia de rendimiento se reduce y luego desaparece con el
Array.Reverse
método a medida que las cadenas se hacen más grandes. Sin embargo, para cadenas de tamaño pequeño a mediano, es difícil superar este método.fuente
La respuesta fácil y agradable es usar el Método de Extensión:
y aquí está la salida:
fuente
Reverse()
yToArray()
están en el orden incorrecto en su muestra de código.Si quieres jugar un juego realmente peligroso, esta es, con mucho, la forma más rápida que existe (alrededor de cuatro veces más rápido que el
Array.Reverse
método). Es un reverso in situ usando punteros.Tenga en cuenta que realmente no lo recomiendo para ningún uso, nunca ( eche un vistazo aquí por algunas razones por las que no debe usar este método ), pero es interesante ver que se puede hacer, y que las cadenas no son realmente inmutables una vez que active el código inseguro.
fuente
unsafe
código que no es malo y que en muchos casos aún lateArray.Reverse
. Mira mi respuesta.Echa un vistazo a la entrada de wikipedia aquí . Implementan el método de extensión String.Reverse. Esto le permite escribir código como este:
También usan la combinación ToCharArray / Reverse que sugieren otras respuestas a esta pregunta. El código fuente se ve así:
fuente
En primer lugar, no necesita llamar
ToCharArray
ya que una cadena ya puede indexarse como una matriz de caracteres, por lo que esto le ahorrará una asignación.La siguiente optimización es usar a
StringBuilder
para evitar asignaciones innecesarias (ya que las cadenas son inmutables, concatenandolas hace una copia de la cadena cada vez). Para optimizar aún más esto, preestablecemos la longitud deStringBuilder
modo que no necesite expandir su búfer.Editar: Datos de rendimiento
Probé esta función y la función usando
Array.Reverse
el siguiente programa simple, dondeReverse1
es una función yReverse2
es la otra:Resulta que para cadenas cortas el
Array.Reverse
método es aproximadamente el doble de rápido que el anterior, y para cadenas más largas la diferencia es aún más pronunciada. Entonces, dado que elArray.Reverse
método es más simple y rápido, te recomiendo que lo uses en lugar de este. Lo dejo aquí solo para mostrar que no es la forma en que debes hacerlo (¡para mi sorpresa!)fuente
Intenta usar Array.
fuente
Por supuesto, puede extender la clase de cadena con el método inverso
fuente
Enumerable.Reverse(input)
es igual ainput.Reverse()
"Mejor" puede depender de muchas cosas, pero aquí hay algunas alternativas cortas más ordenadas de rápido a lento:
fuente
A partir de .NET Core 2.1, hay una nueva forma de invertir una cadena utilizando
string.Create
método.Tenga en cuenta que esta solución no maneja los caracteres combinados Unicode, etc. correctamente, ya que "Les Mise \ u0301rables" se convertiría en "selbarésiM seL". El otro responde para una mejor solución.
Esto esencialmente copia los caracteres de
input
a una nueva cadena e invierte la nueva cadena en el lugar.¿Por qué es
string.Create
útil?Cuando creamos una cadena a partir de una matriz existente, se asigna una nueva matriz interna y se copian los valores. De lo contrario, sería posible mutar una cadena después de su creación (en un entorno seguro). Es decir, en el siguiente fragmento tenemos que asignar una matriz de longitud 10 dos veces, una como el búfer y otra como la matriz interna de la cadena.
string.Create
esencialmente nos permite manipular la matriz interna durante el tiempo de creación de la cadena. Esto es, ya no necesitamos un búfer y, por lo tanto, podemos evitar asignar esa matriz de caracteres.Steve Gordon ha escrito sobre esto con más detalle aquí . También hay un artículo sobre MSDN .
¿Cómo usarlo
string.Create
?El método toma tres parámetros:
char
matriz interna de la nueva cadena y el segundo es el dato (estado) al que pasóstring.Create
.Dentro del delegado podemos especificar cómo se crea la nueva cadena a partir de los datos. En nuestro caso, simplemente copiamos los caracteres de la cadena de entrada a los
Span
utilizados por la nueva cadena. Luego revertimos elSpan
y, por lo tanto, se invierte toda la cadena.Puntos de referencia
Para comparar mi forma propuesta de invertir una cadena con la respuesta aceptada, he escrito dos puntos de referencia utilizando BenchmarkDotNet.
Aquí están los resultados en mi máquina:
Como puede ver, con
ReverseWithStringCreate
solo asignamos la mitad de la memoria utilizada por elReverseWithArray
método.fuente
No te molestes con una función, solo hazlo en su lugar. Nota: La segunda línea arrojará una excepción de argumento en la ventana Inmediato de algunas versiones VS.
fuente
new string
Perdón por la publicación larga, pero esto puede ser interesante
Resultados:
fuente
Salida
Para talla: 10
Para el tamaño: 100
Para el tamaño: 1000
Para el tamaño: 10000
fuente
Reverse(...)
. De lo contrario, buen trabajo.La forma más simple:
fuente
Solución basada en pila.
O
fuente
Tuve que presentar un ejemplo recursivo:
fuente
Qué tal si:
fuente
ToCharArray
primera vez. El enumerador LINQ también es mucho más lento queArray.Reverse()
.He creado un puerto C # de Microsoft.VisualBasic.Strings . No estoy seguro de por qué mantienen funciones tan útiles (desde VB) fuera del System.String en Framework, pero aún bajo Microsoft.VisualBasic. Mismo escenario para las funciones financieras (por ejemplo
Microsoft.VisualBasic.Financial.Pmt()
).fuente
string s = "abo\u0327\u0307\u035d\U0001d166cd"
, que contiene la letrao
seguida de 3 marcas diacríticas combinadas en el BMP y una marca combinada (TIPO COMBINADO DE SÍMBOLO MUSICAL) del plano astral (no BMP) y las mantiene intactas. Pero el método es lento si dichos caracteres solo aparecen al final de una cadena larga, ya que tiene que ir dos veces sobre toda la matriz.Perdón por publicar en este viejo hilo. Estoy practicando un código para una entrevista.
Esto fue lo que se me ocurrió para C #. Mi primera versión antes de refactorizar fue horrible.
En contraste con el
Array.Reverse
siguiente método, parece más rápido con 12 caracteres o menos en la cadena. Después de 13 personajes,Array.Reverse
comienza a ser más rápido y finalmente domina bastante en velocidad. Solo quería señalar aproximadamente dónde comienza a cambiar la velocidad.Con 100 caracteres en la cadena, es más rápido que mi versión x 4. Sin embargo, si supiera que las cadenas siempre tendrían menos de 13 caracteres, usaría la que hice.
Las pruebas se realizaron con
Stopwatch
y 5000000 iteraciones. Además, no estoy seguro de si mi versión maneja sustitutos o situaciones de caracteres combinados conUnicode
codificación.fuente
"Mejor manera" depende de lo que sea más importante para usted en su situación, rendimiento, elegancia, facilidad de mantenimiento, etc.
De todos modos, aquí hay un enfoque usando Array.
fuente
Si alguna vez surgió en una entrevista y le dijeron que no puede usar Array. Sin embargo, creo que este podría ser uno de los más rápidos. No crea nuevas cadenas e itera solo más de la mitad de la matriz (es decir, iteraciones O (n / 2))
fuente
x
, o en su caso,n
no se utiliza. Su algoritmo tiene rendimientof(x) = x + ½x + C
, donde C es algo constante. Como ambosC
y el factor1½
no dependenx
, su algoritmo sí lo esO(x)
. Eso no significa que no será más rápido para ninguna entrada de longitudx
, pero su rendimiento depende linealmente de la longitud de entrada. Para responder a @MarcelValdezOrozco, sí, también lo esO(n)
, aunque copia fragmentos de 16 bytes para mejorar la velocidad (no utiliza una rectamemcpy
en la longitud total).Si tiene una cadena que solo contiene caracteres ASCII, puede usar este método.
fuente
En primer lugar, lo que debe comprender es que str + = redimensionará su memoria de cadena para dejar espacio para 1 carácter adicional. Esto está bien, pero si tiene, por ejemplo, un libro con 1000 páginas que desea revertir, llevará mucho tiempo ejecutarlo.
La solución que algunas personas podrían sugerir es usar StringBuilder. Lo que hace el generador de cadenas cuando realiza un + = es que asigna trozos de memoria mucho más grandes para contener el nuevo carácter, de modo que no necesita realizar una reasignación cada vez que agrega un carácter.
Si realmente quieres una solución rápida y mínima, te sugiero lo siguiente:
En esta solución, hay una asignación de memoria inicial cuando se inicializa char [] y una asignación cuando el constructor de cadenas construye la cadena a partir de la matriz de caracteres.
En mi sistema, ejecuté una prueba para usted que invierte una cadena de 2 750 000 caracteres. Aquí están los resultados de 10 ejecuciones:
StringBuilder: 190K - 200K garrapatas
Char Array: 130K - 160K garrapatas
También ejecuté una prueba para String + = normal pero la abandoné después de 10 minutos sin salida.
Sin embargo, también noté que para cadenas más pequeñas, StringBuilder es más rápido, por lo que tendrá que decidir la implementación en función de la entrada.
Salud
fuente
😀Les Misérables
fuente
fuente