¿Cuál es el método mejor o más conciso para devolver una cadena repetida una cantidad arbitraria de veces?
El siguiente es mi mejor tiro hasta ahora:
function repeat(s, n){
var a = [];
while(a.length < n){
a.push(s);
}
return a.join('');
}
javascript
string
puntilla
fuente
fuente
Respuestas:
Pondría esta función directamente en el objeto String. En lugar de crear una matriz, llenarla y unirla con un carácter vacío, simplemente cree una matriz de la longitud adecuada y únala con la cadena deseada. ¡El mismo resultado, menos proceso!
fuente
String.repeat = function(string, num){ return new Array(parseInt(num) + 1).join(string); };
. Llámalo así:String.repeat('/\', 20)
He probado el rendimiento de todos los enfoques propuestos.
Aquí está la variante más rápida que tengo.
O como función independiente :
Se basa en el algoritmo artistoex . Es realmente rapido. Y cuanto más grande
count
, más rápido va en comparación con elnew Array(count + 1).join(string)
enfoque tradicional .Solo he cambiado 2 cosas:
pattern = this
conpattern = this.valueOf()
(borra una conversión de tipo obvia);if (count < 1)
control de prototypejs a la parte superior de la función para excluir acciones innecesarias en ese caso.UPD
Creé un pequeño patio de pruebas de rendimiento aquí para aquellos interesados.
variable
count
~ 0 .. 100:constante
count
= 1024:Úselo y hágalo aún más rápido si puede :)
fuente
count < 1
caso es una optimización realmente innecesaria.Este problema es un problema de optimización bien conocido / "clásico" para JavaScript, causado por el hecho de que las cadenas de JavaScript son "inmutables" y la adición por concatenación de incluso un solo carácter a una cadena requiere la creación de, incluida la asignación de memoria y la copia a , una cadena completamente nueva.
Desafortunadamente, la respuesta aceptada en esta página es incorrecta, donde "incorrecto" significa un factor de rendimiento de 3x para cadenas simples de un carácter, y 8x-97x para cadenas cortas repetidas más veces, a 300x para oraciones repetidas, e infinitamente incorrecto cuando tomando el límite de las razones de complejidad de los algoritmos
n
hasta el infinito. Además, hay otra respuesta en esta página que es casi correcta (basada en una de las muchas generaciones y variaciones de la solución correcta que ha circulado por Internet en los últimos 13 años). Sin embargo, esta solución "casi correcta" pierde un punto clave del algoritmo correcto y causa una degradación del rendimiento del 50%.JS Performance Results para la respuesta aceptada, la otra respuesta de mejor desempeño (basada en una versión degradada del algoritmo original en esta respuesta), y esta respuesta usando mi algoritmo creado hace 13 años
~ Octubre de 2000 Publiqué un algoritmo para este problema exacto que fue ampliamente adaptado, modificado, y finalmente mal entendido y olvidado. Para solucionar este problema, en agosto de 2008 publiqué un artículo en http://www.webreference.com/programming/javascript/jkm3/3.html que explica el algoritmo y lo utiliza como un ejemplo de optimizaciones simples de JavaScript de uso general. Por ahora, Web Reference ha borrado mi información de contacto e incluso mi nombre de este artículo. Y una vez más, el algoritmo ha sido ampliamente adaptado, modificado, luego mal entendido y en gran parte olvidado.
Dos meses después de la publicación de ese artículo, esta misma pregunta fue publicada en Stack Overflow y pasó desapercibida hasta ahora, cuando aparentemente el algoritmo original para este problema ha sido olvidado nuevamente. La mejor solución disponible en esta página de desbordamiento de pila es una versión modificada de mi solución, posiblemente separada por varias generaciones. Desafortunadamente, las modificaciones arruinaron la optimización de la solución. De hecho, al cambiar la estructura del bucle de mi original, la solución modificada realiza un paso adicional completamente innecesario de duplicación exponencial (uniendo así la cadena más grande utilizada en la respuesta adecuada consigo mismo un tiempo extra y luego descartándola).
A continuación se presenta una discusión sobre algunas optimizaciones de JavaScript relacionadas con todas las respuestas a este problema y en beneficio de todos.
Técnica: evitar referencias a objetos o propiedades de objetos
Para ilustrar cómo funciona esta técnica, utilizamos una función de JavaScript de la vida real que crea cadenas de cualquier longitud necesaria. Y como veremos, ¡se pueden agregar más optimizaciones!
Una función como la que se usa aquí es crear relleno para alinear columnas de texto, formatear dinero o rellenar datos de bloque hasta el límite. Una función de generación de texto también permite la entrada de longitud variable para probar cualquier otra función que opera en texto. Esta función es uno de los componentes importantes del módulo de procesamiento de texto JavaScript.
A medida que avanzamos, cubriremos dos más de las técnicas de optimización más importantes mientras desarrollamos el código original en un algoritmo optimizado para crear cadenas. El resultado final es una función industrial de alto rendimiento que he usado en todas partes, alineando los precios de los artículos y los totales en los formularios de pedido de JavaScript, el formato de datos y el formato de correo electrónico / mensaje de texto y muchos otros usos.
Código original para crear cadenas
stringFill1()
La sintaxis está aquí es clara. Como puede ver, ya hemos usado variables de función local, antes de continuar con más optimizaciones.
Tenga en cuenta que hay una referencia inocente a una propiedad de objeto
s.length
en el código que perjudica su rendimiento. Peor aún, el uso de esta propiedad de objeto reduce la simplicidad del programa al suponer que el lector conoce las propiedades de los objetos de cadena de JavaScript.El uso de esta propiedad de objeto destruye la generalidad del programa de computadora. El programa supone que
x
debe ser una cadena de longitud uno. Esto limita la aplicación de lastringFill1()
función a cualquier cosa, excepto la repetición de caracteres individuales. Incluso los caracteres individuales no se pueden usar si contienen múltiples bytes como la entidad HTML
.El peor problema causado por este uso innecesario de una propiedad de objeto es que la función crea un bucle infinito si se prueba en una cadena de entrada vacía
x
. Para verificar la generalidad, aplique un programa a la menor cantidad de entrada posible. Un programa que falla cuando se le pide que exceda la cantidad de memoria disponible tiene una excusa. Un programa como este que se bloquea cuando se le pide que no produzca nada es inaceptable. A veces, el código bonito es un código venenoso.La simplicidad puede ser un objetivo ambiguo de la programación de computadoras, pero generalmente no lo es. Cuando un programa carece de un nivel razonable de generalidad, no es válido decir: "El programa es lo suficientemente bueno hasta donde llega". Como puede ver, el uso de la
string.length
propiedad evita que este programa funcione en una configuración general y, de hecho, el programa incorrecto está listo para provocar un bloqueo del navegador o del sistema.¿Hay alguna manera de mejorar el rendimiento de este JavaScript y de solucionar estos dos problemas serios?
Por supuesto. Solo usa números enteros.
Código optimizado para crear cadenas
stringFill2()
Código de tiempo para comparar
stringFill1()
ystringFill2()
El éxito hasta ahora de
stringFill2()
stringFill1()
toma 47.297 microsegundos (millonésimas de segundo) para llenar una cadena de 100 bytes, ystringFill2()
toma 27.68 microsegundos para hacer lo mismo. Eso es casi una duplicación en el rendimiento al evitar una referencia a una propiedad de objeto.Técnica: evite agregar cadenas cortas a cadenas largas
Nuestro resultado anterior se veía bien, muy bueno, de hecho. La función mejorada
stringFill2()
es mucho más rápida debido al uso de nuestras dos primeras optimizaciones. ¿Lo creerías si te dijera que se puede mejorar para que sea mucho más rápido de lo que es ahora?Sí, podemos lograr ese objetivo. En este momento necesitamos explicar cómo evitamos agregar cadenas cortas a cadenas largas.
El comportamiento a corto plazo parece ser bastante bueno, en comparación con nuestra función original. A los científicos informáticos les gusta analizar el "comportamiento asintótico" de una función o algoritmo de programa informático, lo que significa estudiar su comportamiento a largo plazo probándolo con entradas más grandes. A veces, sin realizar más pruebas, uno nunca se da cuenta de las formas en que un programa de computadora podría mejorarse. Para ver qué sucederá, crearemos una cadena de 200 bytes.
El problema que aparece con
stringFill2()
Usando nuestra función de temporización, encontramos que el tiempo aumenta a 62.54 microsegundos para una cadena de 200 bytes, en comparación con 27.68 para una cadena de 100 bytes. Parece que el tiempo debería duplicarse para hacer el doble de trabajo, pero en su lugar se triplicó o cuadruplicó. Según la experiencia de programación, este resultado parece extraño, porque en todo caso, la función debería ser un poco más rápida ya que el trabajo se realiza de manera más eficiente (200 bytes por llamada a la función en lugar de 100 bytes por llamada a la función). Este problema tiene que ver con una propiedad insidiosa de las cadenas de JavaScript: las cadenas de JavaScript son "inmutables".
Inmutable significa que no puede cambiar una cadena una vez que se ha creado. Al agregar un byte a la vez, no estamos usando un byte más de esfuerzo. En realidad, estamos recreando la cadena completa más un byte más.
En efecto, para agregar un byte más a una cadena de 100 bytes, se requieren 101 bytes de trabajo. Analicemos brevemente el costo computacional para crear una cadena de
N
bytes. El costo de agregar el primer byte es 1 unidad de esfuerzo computacional. El costo de agregar el segundo byte no es una unidad sino 2 unidades (copiar el primer byte a un nuevo objeto de cadena y agregar el segundo byte). El tercer byte requiere un costo de 3 unidades, etc.C(N) = 1 + 2 + 3 + ... + N = N(N+1)/2 = O(N^2)
. El símboloO(N^2)
se pronuncia Big O de N al cuadrado, y significa que el costo computacional a largo plazo es proporcional al cuadrado de la longitud de la cadena. Crear 100 caracteres requiere 10,000 unidades de trabajo, y crear 200 caracteres requiere 40,000 unidades de trabajo.Es por eso que tomó más del doble de tiempo crear 200 caracteres que 100 caracteres. De hecho, debería haber tardado cuatro veces más. Nuestra experiencia en programación fue correcta en el sentido de que el trabajo se realiza de manera un poco más eficiente para cadenas más largas y, por lo tanto, solo tardó aproximadamente tres veces más. Una vez que la sobrecarga de la llamada a la función se vuelve insignificante en cuanto a la longitud de una cadena que estamos creando, en realidad tomará cuatro veces más tiempo crear una cadena dos veces más larga.
(Nota histórica: este análisis no se aplica necesariamente a las cadenas en el código fuente, por ejemplo
html = 'abcd\n' + 'efgh\n' + ... + 'xyz.\n'
, dado que el compilador del código fuente de JavaScript puede unir las cadenas antes de convertirlas en un objeto de cadena de JavaScript. Hace solo unos años, la implementación de KJS de JavaScript se congelará o bloqueará al cargar largas cadenas de código fuente unidas por signos más. Desde el momento de la computaciónO(N^2)
no fue difícil crear páginas web que sobrecargaran el navegador web Konqueror o Safari, que usaban el núcleo del motor KJS JavaScript. Me encontré con este problema cuando estaba desarrollando un lenguaje de marcado y un analizador de lenguaje de marcado JavaScript, y luego descubrí qué estaba causando el problema cuando escribí mi script para JavaScript Incluye.)Claramente, esta rápida degradación del rendimiento es un gran problema. ¿Cómo podemos lidiar con eso, dado que no podemos cambiar la forma en que JavaScript maneja las cadenas como objetos inmutables? La solución es usar un algoritmo que recrea la cadena lo menos posible.
Para aclarar, nuestro objetivo es evitar agregar cadenas cortas a cadenas largas, ya que para agregar la cadena corta, también se debe duplicar toda la cadena larga.
Cómo funciona el algoritmo para evitar agregar cadenas cortas a cadenas largas
Aquí hay una buena manera de reducir la cantidad de veces que se crean nuevos objetos de cadena. Concatene longitudes de cadena más largas juntas de modo que se agregue más de un byte a la vez a la salida.
Por ejemplo, para hacer una cadena de longitud
N = 9
:Hacer esto requirió crear una cadena de longitud 1, crear una cadena de longitud 2, crear una cadena de longitud 4, crear una cadena de longitud 8 y, finalmente, crear una cadena de longitud 9. ¿Cuánto hemos ahorrado?
Viejo costo
C(9) = 1 + 2 + 3 + 4 + 5 + 6 + 7 + 9 = 45
.Nuevo costo
C(9) = 1 + 2 + 4 + 8 + 9 = 24
.Tenga en cuenta que tuvimos que agregar una cadena de longitud 1 a una cadena de longitud 0, luego una cadena de longitud 1 a una cadena de longitud 1, luego una cadena de longitud 2 a una cadena de longitud 2, luego una cadena de longitud 4 a una cadena de longitud 4, luego una cadena de longitud 8 a una cadena de longitud 1, para obtener una cadena de longitud 9. Lo que estamos haciendo puede resumirse como evitar agregar cadenas cortas a cadenas largas, o en otro palabras, tratando de concatenar cadenas que son de igual o casi igual longitud.
Para el antiguo costo computacional encontramos una fórmula
N(N+1)/2
. ¿Existe una fórmula para el nuevo costo? Sí, pero es complicado. Lo importante es que lo esO(N)
, por lo que duplicar la longitud de la cadena duplicará aproximadamente la cantidad de trabajo en lugar de cuadruplicarlo.El código que implementa esta nueva idea es casi tan complicado como la fórmula del costo computacional. Cuando lo lea, recuerde que
>>= 1
significa desplazarse a la derecha en 1 byte. Entonces, sin = 10011
es un número binario, entoncesn >>= 1
da como resultado el valorn = 1001
.La otra parte del código que tal vez no reconozca es el bit a bit y el operador, escrito
&
. La expresiónn & 1
evalúa verdadero si el último dígito binario den
es 1, y falso si el último dígito binario den
es 0.Nueva altamente eficientes en
stringFill3()
función deParece feo a simple vista, pero su rendimiento es nada menos que encantador.
Veamos qué tan bien funciona esta función. Después de ver los resultados, es probable que nunca olvide la diferencia entre un
O(N^2)
algoritmo y unO(N)
algoritmo.stringFill1()
toma 88.7 microsegundos (millonésimas de segundo) para crear una cadena de 200 bytes,stringFill2()
toma 62.54 ystringFill3()
toma solo 4.608. ¿Qué hizo que este algoritmo fuera mucho mejor? Todas las funciones aprovecharon el uso de variables de función local, pero aprovechar las técnicas de optimización segunda y tercera agregó una mejora de veinte veces al rendimiento destringFill3()
.Análisis más profundo
¿Qué hace que esta función particular expulse a la competencia del agua?
Como he mencionado, la razón por la que ambas funciones
stringFill1()
y sustringFill2()
ejecución son tan lentas es que las cadenas de JavaScript son inmutables. La memoria no se puede reasignar para permitir que se agregue un byte más a la vez a los datos de cadena almacenados por JavaScript. Cada vez que se agrega un byte más al final de la cadena, la cadena completa se regenera de principio a fin.Por lo tanto, para mejorar el rendimiento del script, uno debe calcular previamente cadenas de mayor longitud concatenando dos cadenas juntas antes de tiempo, y luego acumulando recursivamente la longitud de cadena deseada.
Por ejemplo, para crear una cadena de bytes de 16 letras, primero se calculará previamente una cadena de dos bytes. Luego, la cadena de dos bytes se reutilizaría para calcular previamente una cadena de cuatro bytes. Luego, la cadena de cuatro bytes se reutilizaría para calcular previamente una cadena de ocho bytes. Finalmente, dos cadenas de ocho bytes se reutilizarían para crear la nueva cadena deseada de 16 bytes. En total, se tuvieron que crear cuatro cadenas nuevas, una de longitud 2, una de longitud 4, una de longitud 8 y una de longitud 16. El costo total es 2 + 4 + 8 + 16 = 30.
A la larga, esta eficiencia se puede calcular sumando en orden inverso y utilizando una serie geométrica que comience con un primer término a1 = N y que tenga una relación común de r = 1/2. La suma de una serie geométrica viene dada por
a_1 / (1-r) = 2N
.Esto es más eficiente que agregar un carácter para crear una nueva cadena de longitud 2, crear una nueva cadena de longitud 3, 4, 5, y así sucesivamente, hasta 16. El algoritmo anterior utilizó ese proceso de agregar un solo byte a la vez , y el costo total sería
n (n + 1) / 2 = 16 (17) / 2 = 8 (17) = 136
.Obviamente, 136 es un número mucho mayor que 30, por lo que el algoritmo anterior toma mucho, mucho más tiempo para construir una cadena.
Para comparar los dos métodos, puede ver qué tan rápido es el algoritmo recursivo (también llamado "divide y vencerás") en una cadena de longitud 123,457. En mi computadora FreeBSD, este algoritmo, implementado en la
stringFill3()
función, crea la cadena en 0.001058 segundos, mientras que lastringFill1()
función original crea la cadena en 0.0808 segundos. La nueva función es 76 veces más rápida.La diferencia en el rendimiento aumenta a medida que la longitud de la cadena se hace más grande. En el límite a medida que se crean cadenas cada vez más grandes, la función original se comporta aproximadamente como
C1
(constantes) vecesN^2
, y la nueva función se comporta comoC2
(constantes) vecesN
.De nuestro experimento podemos determinar el valor de
C1
serC1 = 0.0808 / (123457)2 = .00000000000530126997
y el valor deC2
serC2 = 0.001058 / 123457 = .00000000856978543136
. En 10 segundos, la nueva función podría crear una cadena que contiene 1,166,890,359 caracteres. Para crear esta misma cadena, la función anterior necesitaría 7.218.384 segundos de tiempo.¡Esto es casi tres meses en comparación con diez segundos!
Solo respondo (varios años tarde) porque mi solución original a este problema ha estado flotando en Internet durante más de 10 años, y aparentemente los pocos que la recuerdan todavía no la entienden. Pensé que al escribir un artículo al respecto aquí ayudaría:
Optimizaciones de rendimiento para JavaScript de alta velocidad / Página 3
Desafortunadamente, algunas de las otras soluciones presentadas aquí todavía son algunas de las que tomarían tres meses para producir la misma cantidad de salida que una solución adecuada crea en 10 segundos.
Quiero tomarme el tiempo de reproducir parte del artículo aquí como respuesta canónica en Stack Overflow.
Tenga en cuenta que el algoritmo de mejor rendimiento aquí se basa claramente en mi algoritmo y probablemente fue heredado de la adaptación de tercera o cuarta generación de otra persona. Desafortunadamente, las modificaciones resultaron en la reducción de su rendimiento. La variación de mi solución presentada aquí tal vez no entendió mi
for (;;)
expresión confusa que se parece al bucle infinito principal de un servidor escrito en C, y que simplemente fue diseñada para permitir una declaración de interrupción cuidadosamente posicionada para el control del bucle, la forma más compacta de evite replicar exponencialmente la cadena un tiempo innecesario adicional.fuente
Este es bastante eficiente
fuente
¡Buenas noticias! ahora
String.prototype.repeat
es parte de JavaScript .El método es compatible con todos los principales navegadores, excepto Internet Explorer y Android Webview. Para obtener una lista actualizada, consulte MDN: String.prototype.repeat> Compatibilidad del navegador .
MDN tiene un polyfill para navegadores sin soporte.
fuente
String.prototype.repeat ahora es ES6 Standard.
fuente
Ampliando la solución de P.Bailey :
De esta manera, debe estar a salvo de los tipos de argumentos inesperados:
EDITAR: ¡Créditos a Jerone por su elegante
++num
idea!fuente
String.prototype.repeat = function(n){return new Array(isNaN(n) ? 1 : ++n).join(this);}
Utilizar
Array(N+1).join("string_to_repeat")
fuente
Así es como se repite la cadena varias veces con delimitador.
fuente
Aquí hay una mejora del 5-7% en la respuesta de disfated.
Desenrolle el bucle deteniéndose en
count > 1
y realice unaresult += pattnern
concat adicional después del bucle. Esto evitará que los bucles finales nopattern += pattern
hayan sido utilizados previamente sin tener que usar un costoso if-check. El resultado final se vería así:Y aquí está el violín de disfated bifurcado para la versión desenrollada: http://jsfiddle.net/wsdfg/
fuente
fuente
var r=s; for (var a=1;...
:)))) De todos modos, de acuerdo con esta prueba ( jsperf.com/string-repeat/2 ), hacer un bucle simple para concatenación de cadenas como lo que sugirió parece ser mucho más rápido en Chrome en comparación con el uso de Array .unirse.Pruebas de los distintos métodos:
fuente
Aquí está la versión segura de JSLint
fuente
Para todos los navegadores
Esto es lo más conciso posible:
Si también te importa el rendimiento, este es un enfoque mucho mejor:
Si desea comparar el rendimiento de ambas opciones, consulte este Fiddle y este Fiddle para las pruebas de referencia. ¡Durante mis propias pruebas, la segunda opción fue aproximadamente 2 veces más rápida en Firefox y aproximadamente 4 veces más rápida en Chrome!
Solo para navegadores modernos:
En los navegadores modernos, ahora también puede hacer esto:
Esta opción no solo es más corta que las otras dos, sino que es incluso más rápida que la segunda opción.
Desafortunadamente, no funciona en ninguna versión de Internet Explorer. Los números en la tabla especifican la primera versión del navegador que soporta totalmente este método :
fuente
Puedes probarlo en JSFiddle . El punto de referencia contra el hacky
Array.join
y el mío es, en términos generales, 10 (Chrome) a 100 (Safari) a 200 (Firefox) veces más rápido (dependiendo del navegador).fuente
Solo otra función de repetición:
fuente
ES2015
Se ha realizado esterepeat()
método!http://www.ecma-international.org/ecma-262/6.0/#sec-string.prototype.repeat
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ Cadena / repetir
http://www.w3schools.com/jsref/jsref_repeat.asp
fuente
Este puede ser el recursivo más pequeño:
fuente
Violín: http://jsfiddle.net/3Y9v2/
fuente
Concatenación recursiva simple
Solo quería darle una fiesta e hice esto:
No puedo decir que lo haya pensado mucho, y probablemente muestra :-)
Esto es posiblemente mejor
Y es muy parecido a una respuesta ya publicada: lo sé.
Pero, ¿por qué ser recursivo?
¿Y qué tal un pequeño comportamiento predeterminado también?
Porque , aunque el método no recursivo manejará repeticiones arbitrariamente grandes sin alcanzar los límites de la pila de llamadas, es mucho más lento.
¿Por qué me molesté en agregar más métodos que no son la mitad de inteligentes que los ya publicados?
En parte para mi propia diversión, y en parte para señalar de la manera más simple, sé que hay muchas maneras de desollar a un gato, y dependiendo de la situación, es muy posible que el método aparentemente mejor no sea el ideal.
Un método relativamente rápido y sofisticado puede bloquearse y quemarse efectivamente bajo ciertas circunstancias, mientras que un método más lento y simple puede hacer el trabajo, eventualmente.
Algunos métodos pueden ser poco más que explota, y como tal propenso a ser fijo fuera de la existencia, y otros métodos pueden funcionar muy bien en todas las condiciones, pero están construidos de manera que uno simplemente tiene ni idea de cómo funciona.
"¿Y qué si no sé cómo funciona?"
¿Seriamente?
JavaScript tiene uno de sus mayores puntos fuertes; es muy tolerante con el mal comportamiento, y tan flexible que se doblará hacia atrás para devolver resultados, ¡cuando podría haber sido mejor para todos si se hubiera roto!
"Con gran poder, viene una gran responsabilidad" ;-)
Pero más en serio e importante, aunque las preguntas generales como esta conducen a la genialidad en forma de respuestas inteligentes que, si nada más, expanden el conocimiento y los horizontes, al final, la tarea en cuestión, el guión práctico que utiliza el método resultante. puede requerir un poco menos o un poco más inteligente de lo que se sugiere.
Estos algoritmos "perfectos" son divertidos y todo, pero "una talla para todos" rara vez será mejor que hecho a medida.
Este sermón fue presentado por cortesía de la falta de sueño y un interés pasajero. ¡Sal y codifica!
fuente
En primer lugar, las preguntas del OP parecen ser sobre concisión, lo que entiendo que significa "simple y fácil de leer", mientras que la mayoría de las respuestas parecen ser sobre eficiencia, lo que obviamente no es lo mismo y también creo que a menos que implemente algo muy Algoritmos específicos de manipulación de datos grandes, no debería preocuparle cuando implemente funciones JavaScript de manipulación de datos básicos. La concisión es mucho más importante.
En segundo lugar, como observó André Laszlo, String.repeat es parte de ECMAScript 6 y ya está disponible en varias implementaciones populares, por lo que la implementación más concisa
String.repeat
es no implementarlo ;-)Por último, si necesita admitir hosts que no ofrecen la implementación ECMAScript 6, el polyfill de MDN mencionado por André Laszlo es todo menos conciso.
Entonces, sin más preámbulos, aquí está mi polyfill conciso :
Sí, esto es una recursión. Me gustan las recurrencias: son simples y si se hacen correctamente son fáciles de entender. En cuanto a la eficiencia, si el lenguaje lo admite, pueden ser muy eficientes si se escriben correctamente.
Según mis pruebas, este método es ~ 60% más rápido que el
Array.join
enfoque. Aunque obviamente no se acerca a la implementación de disfated, es mucho más simple que ambos.Mi configuración de prueba es el nodo v0.10, que utiliza el "Modo estricto" (creo que permite algún tipo de TCO ), solicitando
repeat(1000)
una cadena de 10 caracteres un millón de veces.fuente
Si cree que todas esas definiciones de prototipos, creaciones de matrices y operaciones de unión son excesivas, simplemente use un código de línea único donde lo necesite. Cadena S que se repite N veces:
fuente
Array(N + 1).join(str)
método si no es un cuello de botella de rendimiento). Si existe la menor posibilidad de que lo vaya a usar dos veces, muévalo a una función con el nombre apropiado.Use Lodash para la funcionalidad de la utilidad Javascript, como repetir cadenas.
Lodash ofrece un rendimiento agradable y compatibilidad con ECMAScript.
Lo recomiendo para el desarrollo de UI y también funciona bien en el lado del servidor.
Aquí se explica cómo repetir la cadena "yo" 2 veces con Lodash:
fuente
Solución recursiva usando divide y vencerás:
fuente
Vine aquí al azar y nunca tuve una razón para repetir un char en javascript antes.
Me impresionó la forma en que artistoex lo hizo y los resultados desvalorizados. Noté que la última cadena de concat era innecesaria, como también señaló Dennis.
Noté algunas cosas más cuando jugué con la muestra desfavorecida junta.
Los resultados variaron bastante a menudo favoreciendo la última carrera y algoritmos similares a menudo competirían por la posición. Una de las cosas que cambié fue en lugar de usar el conteo generado por JSLitmus como semilla para las llamadas; Como el recuento se generó de manera diferente para los diversos métodos, puse un índice. Esto hizo la cosa mucho más confiable. Luego miré para asegurar que se pasaran cadenas de diferentes tamaños a las funciones. Esto evitó algunas de las variaciones que vi, donde algunos algoritmos funcionaron mejor en caracteres únicos o cadenas más pequeñas. Sin embargo, los 3 métodos principales funcionaron bien independientemente del tamaño de la cadena.
Conjunto de prueba bifurcado
http://jsfiddle.net/schmide/fCqp3/134/
Luego incluí el arreglo de Dennis y decidí ver si podía encontrar una manera de buscar un poco más.
Dado que javascript realmente no puede optimizar las cosas, la mejor manera de mejorar el rendimiento es evitar las cosas manualmente. Si tomé los primeros 4 resultados triviales fuera del ciclo, podría evitar 2-4 almacenes de cadenas y escribir el almacén final directamente en el resultado.
Esto resultó en una mejora del 1-2% en promedio sobre la corrección de Dennis. Sin embargo, diferentes ejecuciones y diferentes navegadores mostrarían una variación lo suficientemente justa como para que este código adicional no valga la pena el esfuerzo sobre los 2 algoritmos anteriores.
Una tabla
Editar: Hice esto principalmente bajo cromo. Firefox e IE a menudo favorecerán a Dennis en un par de%.
fuente
Método simple:
fuente
Las personas complican demasiado esto hasta un punto ridículo o desperdician el rendimiento. Matrices? Recursividad? Tienes que estar bromeando.
Editar. Realicé algunas pruebas simples para comparar con la versión bit a bit publicada por artistoex / disfated y un montón de otras personas. Este último era solo marginalmente más rápido, pero con órdenes de magnitud más eficientes en memoria. Para 1000000 repeticiones de la palabra 'bla', el proceso de Nodo subió a 46 megabytes con el algoritmo de concatenación simple (arriba), pero solo 5.5 megabytes con el algoritmo logarítmico. Este último es definitivamente el camino a seguir. Reposicionándolo por razones de claridad:
fuente
string += string
mitad de tiempo redundante .Concatenando cadenas basadas en un número.
¡Espero que ayude!
fuente
Con ES8 también podría usar
padStart
opadEnd
para esto. p.ej.fuente