Qual é o método melhor ou mais conciso para retornar uma sequência repetida várias vezes?
O seguinte é o meu melhor tiro até agora:
function repeat(s, n){
var a = [];
while(a.length < n){
a.push(s);
}
return a.join('');
}
javascript
string
Brad
fonte
fonte
Respostas:
Eu colocaria essa função no objeto String diretamente. Em vez de criar uma matriz, preenchê-la e uni-la com um caractere vazio, basta criar uma matriz com o comprimento adequado e associá-la à string desejada. Mesmo resultado, menos processo!
fonte
String.repeat = function(string, num){ return new Array(parseInt(num) + 1).join(string); };
. Chame assim:String.repeat('/\', 20)
Eu testei o desempenho de todas as abordagens propostas.
Aqui está a variante mais rápida que eu tenho.
Ou como função autônoma :
É baseado no algoritmo artistoex . É realmente rápido. E quanto maior
count
, mais rápido ele se compara ànew Array(count + 1).join(string)
abordagem tradicional .Eu mudei apenas duas coisas:
pattern = this
porpattern = this.valueOf()
(limpa uma conversão de tipo óbvia);if (count < 1)
verificação de prototypejs na parte superior da função para excluir ações desnecessárias nesse caso.UPD
Criou um pequeno parque de teste de desempenho aqui para aqueles que interessados.
variável
count
~ 0 .. 100:constante
count
= 1024:Use-o e torne-o ainda mais rápido, se puder :)
fonte
count < 1
caso é realmente otimização desnecessária.Esse problema é um problema de otimização conhecido / "clássico" para JavaScript, causado pelo fato de que as strings JavaScript são "imutáveis" e a adição pela concatenação de um único caractere a uma string exige a criação de, incluindo alocação de memória e cópia para , uma nova sequência inteira.
Infelizmente, a resposta aceita nesta página está errada, onde "errado" significa um fator de desempenho de 3x para seqüências de caracteres simples de um caractere e 8x-97x para seqüências curtas repetidas mais vezes, a 300x para repetir frases e infinitamente errado quando tomando o limite das proporções de complexidade dos algoritmos como
n
vai para o infinito. Além disso, há outra resposta nesta página que está quase correta (com base em uma das muitas gerações e variações da solução correta que circula pela Internet nos últimos 13 anos). No entanto, essa solução "quase correta" perde um ponto-chave do algoritmo correto, causando uma degradação de 50% no desempenho.Resultados de desempenho de JS para a resposta aceita, a outra resposta com melhor desempenho (com base em uma versão degradada do algoritmo original nesta resposta) e essa resposta usando meu algoritmo criado há 13 anos
Em outubro de 2000, publiquei um algoritmo para esse problema exato, que foi amplamente adaptado, modificado e, eventualmente, pouco compreendido e esquecido. Para corrigir esse problema, em agosto de 2008, publiquei um artigo http://www.webreference.com/programming/javascript/jkm3/3.html explicando o algoritmo e usando-o como um exemplo de otimizações simples de JavaScript de uso geral. Até agora, a Referência da Web limpou minhas informações de contato e até mesmo meu nome neste artigo. E mais uma vez, o algoritmo foi amplamente adaptado, modificado, depois mal compreendido e amplamente esquecido.
Dois meses após a publicação desse artigo, essa mesma pergunta foi postada no Stack Overflow e voou sob meu radar até agora, quando aparentemente o algoritmo original para esse problema foi novamente esquecido. A melhor solução disponível nesta página Stack Overflow é uma versão modificada da minha solução, possivelmente separada por várias gerações. Infelizmente, as modificações arruinaram a otimização da solução. De fato, ao alterar a estrutura do loop do meu original, a solução modificada executa uma etapa extra completamente desnecessária de duplicação exponencial (juntando, assim, a maior cadeia usada na resposta adequada por um tempo extra e descartando-a).
Abaixo segue uma discussão sobre algumas otimizações de JavaScript relacionadas a todas as respostas para esse problema e para o benefício de todos.
Técnica: Evite referências a objetos ou propriedades de objetos
Para ilustrar como essa técnica funciona, usamos uma função JavaScript da vida real que cria seqüências de caracteres de qualquer tamanho necessário. E como veremos, mais otimizações podem ser adicionadas!
Uma função como a usada aqui é criar preenchimento para alinhar colunas de texto, formatar dinheiro ou preencher dados de bloco até o limite. Uma função de geração de texto também permite a entrada de comprimento variável para testar qualquer outra função que opere no texto. Essa função é um dos componentes importantes do módulo de processamento de texto JavaScript.
À medida que prosseguimos, abordaremos mais duas das técnicas de otimização mais importantes, enquanto desenvolvemos o código original em um algoritmo otimizado para a criação de strings. O resultado final é uma função de alto desempenho e força industrial que já usei em todos os lugares - alinhando preços e totais de itens em formulários de pedidos JavaScript, formatação de dados e formatação de email / mensagem de texto e muitos outros usos.
Código original para criar strings
stringFill1()
A sintaxe aqui é clara. Como você pode ver, já usamos variáveis de função local, antes de avançar para mais otimizações.
Esteja ciente de que há uma referência inocente a uma propriedade de objeto
s.length
no código que prejudica seu desempenho. Pior ainda, o uso dessa propriedade de objeto reduz a simplicidade do programa ao assumir que o leitor conhece as propriedades dos objetos de sequência JavaScript.O uso dessa propriedade de objeto destrói a generalidade do programa de computador. O programa assume que
x
deve ser uma sequência de comprimento um. Isso limita a aplicação dastringFill1()
função a qualquer coisa, exceto a repetição de caracteres únicos. Mesmo caracteres únicos não podem ser usados se eles contiverem vários bytes como a entidade HTML
.O pior problema causado por esse uso desnecessário de uma propriedade de objeto é que a função cria um loop infinito se testada em uma sequência de entrada vazia
x
. Para verificar a generalidade, aplique um programa à menor quantidade possível de entrada. Um programa que trava quando solicitado a exceder a quantidade de memória disponível tem uma desculpa. Um programa como este, que trava quando solicitado a produzir nada, é inaceitável. Às vezes, um código bonito é um código venenoso.A simplicidade pode ser um objetivo ambíguo da programação de computadores, mas geralmente não é. Quando um programa não possui um nível razoável de generalidade, não é válido dizer: "O programa é bom o suficiente na medida do possível". Como você pode ver, o uso da
string.length
propriedade impede que este programa funcione em uma configuração geral e, de fato, o programa incorreto está pronto para causar uma falha no navegador ou no sistema.Existe uma maneira de melhorar o desempenho desse JavaScript e cuidar desses dois problemas sérios?
Claro. Basta usar números inteiros.
Código otimizado para criar strings
stringFill2()
Código de tempo para comparar
stringFill1()
estringFill2()
O sucesso até agora de
stringFill2()
stringFill1()
leva 47,297 microssegundos (milionésimos de segundo) para preencher uma cadeia de 100 bytes estringFill2()
leva 27,68 microssegundos para fazer a mesma coisa. Isso quase dobrou o desempenho, evitando a referência a uma propriedade de objeto.Técnica: Evite adicionar cadeias curtas a longas
Nosso resultado anterior parecia bom - muito bom, de fato. A função aprimorada
stringFill2()
é muito mais rápida devido ao uso das nossas duas primeiras otimizações. Você acreditaria se eu lhe dissesse que pode ser melhorado muitas vezes mais rápido do que é agora?Sim, podemos alcançar esse objetivo. No momento, precisamos explicar como evitar anexar cadeias curtas a longas.
O comportamento a curto prazo parece ser bastante bom, em comparação com a nossa função original. Os cientistas da computação gostam de analisar o "comportamento assintótico" de uma função ou algoritmo de programa de computador, o que significa estudar seu comportamento a longo prazo, testando-o com entradas maiores. Às vezes, sem fazer mais testes, nunca se percebe como um programa de computador pode ser aprimorado. Para ver o que vai acontecer, vamos criar uma string de 200 bytes.
O problema que aparece com
stringFill2()
Usando nossa função de temporização, descobrimos que o tempo aumenta para 62,54 microssegundos para uma sequência de 200 bytes, em comparação com 27,68 para uma sequência de 100 bytes. Parece que o tempo deve ser dobrado para fazer o dobro do trabalho, mas, em vez disso, é triplicado ou quadruplicado. Da experiência em programação, esse resultado parece estranho, porque, se houver algo, a função deve ser um pouco mais rápida, pois o trabalho está sendo realizado com mais eficiência (200 bytes por chamada de função em vez de 100 bytes por chamada de função). Esse problema tem a ver com uma propriedade insidiosa de strings JavaScript: as strings JavaScript são "imutáveis".
Imutável significa que você não pode alterar uma sequência depois que ela é criada. Ao adicionar um byte de cada vez, não estamos gastando mais um byte de esforço. Na verdade, estamos recriando a string inteira mais um byte.
Com efeito, para adicionar mais um byte a uma string de 100 bytes, são necessários 101 bytes de trabalho. Vamos analisar brevemente o custo computacional para criar uma sequência de
N
bytes. O custo da adição do primeiro byte é de 1 unidade de esforço computacional. O custo de adicionar o segundo byte não é uma unidade, mas duas unidades (copiar o primeiro byte para um novo objeto de string e adicionar o segundo byte). O terceiro byte requer um custo de 3 unidades, etc.C(N) = 1 + 2 + 3 + ... + N = N(N+1)/2 = O(N^2)
. O símboloO(N^2)
é pronunciado Big O of N ao quadrado e significa que o custo computacional a longo prazo é proporcional ao quadrado do comprimento da string. Criar 100 caracteres requer 10.000 unidades de trabalho e criar 200 caracteres requer 40.000 unidades de trabalho.É por isso que demorou mais que o dobro para criar 200 caracteres e 100 caracteres. De fato, deveria ter levado quatro vezes mais. Nossa experiência em programação estava correta, pois o trabalho está sendo realizado de forma um pouco mais eficiente para seqüências mais longas e, portanto, levou apenas cerca de três vezes mais. Quando a sobrecarga da chamada de função se torna insignificante quanto ao comprimento de uma string que estamos criando, na verdade levará quatro vezes mais tempo para criar uma string com o dobro do tempo.
(Nota histórica: Essa análise não se aplica necessariamente a cadeias de caracteres no código-fonte, como
html = 'abcd\n' + 'efgh\n' + ... + 'xyz.\n'
, uma vez que o compilador de código-fonte JavaScript pode unir as cadeias antes de transformá-las em um objeto de cadeia JavaScript. Há alguns anos, a implementação do KJS de O JavaScript congelava ou falhava ao carregar longas seqüências de código-fonte unidas por sinais de mais.Como o tempo computacionalO(N^2)
não era difícil de criar páginas da Web que sobrecarregavam o navegador Konqueror ou o Safari, que usava o núcleo do mecanismo JavaScript do KJS. deparei com esse problema quando eu estava desenvolvendo uma linguagem de marcação e um analisador de linguagem de marcação JavaScript e descobri o que estava causando o problema quando escrevi meu script para o JavaScript Inclui.Claramente, essa rápida degradação do desempenho é um enorme problema. Como podemos lidar com isso, já que não podemos mudar a maneira do JavaScript de manipular strings como objetos imutáveis? A solução é usar um algoritmo que recria a string o menor número de vezes possível.
Para esclarecer, nosso objetivo é evitar adicionar cadeias curtas a longas, pois, para adicionar a cadeia curta, toda a cadeia longa também deve ser duplicada.
Como o algoritmo funciona para evitar adicionar cadeias curtas a longas
Aqui está uma boa maneira de reduzir o número de vezes que novos objetos de string são criados. Concatene comprimentos maiores de cadeia juntos para que mais de um byte de cada vez seja adicionado à saída.
Por exemplo, para criar uma sequência de comprimento
N = 9
:Para isso, era necessário criar uma sequência de comprimento 1, criar uma sequência de comprimento 2, criar uma sequência de comprimento 4, criar uma sequência de comprimento 8 e, finalmente, criar uma sequência de comprimento 9. Quanto custo economizamos?
Custo antigo
C(9) = 1 + 2 + 3 + 4 + 5 + 6 + 7 + 9 = 45
.Novo custo
C(9) = 1 + 2 + 4 + 8 + 9 = 24
.Observe que tivemos que adicionar uma string de comprimento 1 a uma string de comprimento 0, depois uma string de comprimento 1 a uma string de comprimento 1, depois uma string de comprimento 2 a uma string de comprimento 2, depois uma string de comprimento 4 para uma cadeia de comprimento 4, depois uma cadeia de comprimento 8 para uma cadeia de comprimento 1, a fim de obter uma cadeia de comprimento 9. O que estamos fazendo pode ser resumido como evitar adicionar cadeias curtas a cadeias longas ou em outras palavras, tentando concatenar cadeias de comprimento igual ou quase igual.
Para o antigo custo computacional, encontramos uma fórmula
N(N+1)/2
. Existe uma fórmula para o novo custo? Sim, mas é complicado. O importante é que simO(N)
, e dobrar o comprimento da corda dobrará aproximadamente a quantidade de trabalho, em vez de quadruplicar.O código que implementa essa nova idéia é quase tão complicado quanto a fórmula para o custo computacional. Ao ler, lembre-se de que isso
>>= 1
significa mudar para a direita em 1 byte. Então, sen = 10011
é um número binário,n >>= 1
resulta no valorn = 1001
.A outra parte do código que você talvez não reconheça é o operador bit a bit e escrito
&
. A expressãon & 1
avalia true se o último dígito binário den
for 1 e false se o último dígito binário den
for 0.Nova
stringFill3()
função altamente eficienteParece feio para os olhos destreinados, mas seu desempenho é nada menos que adorável.
Vamos ver o quão bem essa função executa. Depois de ver os resultados, é provável que você nunca esqueça a diferença entre um
O(N^2)
algoritmo e umO(N)
algoritmo.stringFill1()
leva 88,7 microssegundos (milionésimos de segundo) para criar uma sequência de 200 bytes,stringFill2()
leva 62,54 estringFill3()
leva apenas 4,608. O que tornou esse algoritmo muito melhor? Todas as funções tiraram vantagem do uso de variáveis de função locais, mas tirar proveito da segunda e terceira técnicas de otimização adicionou uma melhoria de vinte vezes ao desempenho destringFill3()
.Análise mais profunda
O que faz com que essa função em particular afaste a concorrência da água?
Como já mencionei, a razão para que ambas as funções,
stringFill1()
estringFill2()
, corra tão lentamente é que as cordas JavaScript são imutáveis. A memória não pode ser realocada para permitir que mais um byte de cada vez seja anexado aos dados da string armazenados pelo JavaScript. Toda vez que mais um byte é adicionado ao final da string, a string inteira é regenerada do começo ao fim.Portanto, para melhorar o desempenho do script, é necessário pré-computar cadeias de comprimento mais longas concatenando duas cadeias antes do tempo e depois construindo recursivamente o comprimento de cadeia desejado.
Por exemplo, para criar uma sequência de 16 bytes, primeiro uma sequência de dois bytes seria pré-computada. Em seguida, a cadeia de dois bytes seria reutilizada para pré-calcular uma cadeia de quatro bytes. Em seguida, a cadeia de quatro bytes seria reutilizada para pré-calcular uma cadeia de oito bytes. Finalmente, duas seqüências de oito bytes seriam reutilizadas para criar a nova sequência desejada de 16 bytes. No total, quatro novas cadeias tiveram que ser criadas, uma de comprimento 2, uma de comprimento 4, uma de comprimento 8 e uma de comprimento 16. O custo total é de 2 + 4 + 8 + 16 = 30.
A longo prazo, essa eficiência pode ser calculada adicionando-se na ordem inversa e usando uma série geométrica começando com o primeiro termo a1 = N e tendo uma razão comum de r = 1/2. A soma de uma série geométrica é dada por
a_1 / (1-r) = 2N
.Isso é mais eficiente do que adicionar um caractere para criar uma nova cadeia de comprimento 2, criando uma nova cadeia de comprimento 3, 4, 5 e assim por diante, até 16. O algoritmo anterior usou esse processo de adição de um único byte por vez , e o custo total seria
n (n + 1) / 2 = 16 (17) / 2 = 8 (17) = 136
.Obviamente, 136 é um número muito maior que 30 e, portanto, o algoritmo anterior leva muito, muito mais tempo para construir uma string.
Para comparar os dois métodos, é possível ver com que rapidez o algoritmo recursivo (também chamado de "dividir e conquistar") está em uma sequência de comprimento 123.457. No meu computador com FreeBSD, esse algoritmo, implementado na
stringFill3()
função, cria a string em 0,001058 segundos, enquanto astringFill1()
função original cria a string em 0,0808 segundos. A nova função é 76 vezes mais rápida.A diferença no desempenho aumenta à medida que o comprimento da string se torna maior. No limite, à medida que cadeias cada vez maiores são criadas, a função original se comporta aproximadamente como
C1
tempos (constantes)N^2
e a nova função se comporta comoC2
tempos (constantes)N
.Do nosso experimento, podemos determinar o valor de
C1
serC1 = 0.0808 / (123457)2 = .00000000000530126997
e o valor deC2
serC2 = 0.001058 / 123457 = .00000000856978543136
. Em 10 segundos, a nova função poderia criar uma sequência contendo 1.166.890.359 caracteres. Para criar essa mesma string, a função antiga precisaria de 7.218.384 segundos de tempo.São quase três meses em comparação com dez segundos!
Só estou respondendo (vários anos atrasado) porque minha solução original para esse problema está flutuando na Internet há mais de 10 anos e, aparentemente, ainda é pouco compreendida pelos poucos que se lembram dele. Eu pensei que, escrevendo um artigo sobre o assunto aqui, eu ajudaria:
Otimizações de desempenho para JavaScript de alta velocidade / Página 3
Infelizmente, algumas das outras soluções apresentadas aqui ainda são aquelas que levariam três meses para produzir a mesma quantidade de saída que uma solução adequada cria em 10 segundos.
Quero dedicar um tempo para reproduzir parte do artigo aqui como uma resposta canônica no Stack Overflow.
Observe que o algoritmo de melhor desempenho aqui é claramente baseado no meu algoritmo e provavelmente foi herdado da adaptação de terceira ou quarta geração de outra pessoa. Infelizmente, as modificações resultaram na redução de seu desempenho. A variação da minha solução apresentada aqui talvez não entenda minha
for (;;)
expressão confusa que se parece com o loop infinito principal de um servidor escrito em C e que foi simplesmente projetada para permitir uma declaração de interrupção cuidadosamente posicionada para controle de loop, a maneira mais compacta de evite replicar exponencialmente a string um tempo extra desnecessário.fonte
Este é bastante eficiente
fonte
Boas notícias!
String.prototype.repeat
é agora uma parte de JavaScript .O método é suportado por todos os principais navegadores, exceto o Internet Explorer e o Android Webview. Para obter uma lista atualizada, consulte MDN: String.prototype.repeat> Compatibilidade do navegador .
O MDN possui um polyfill para navegadores sem suporte.
fonte
String.prototype.repeat agora é o ES6 Standard.
fonte
Expandindo a solução de P.Bailey :
Dessa forma, você deve estar protegido contra tipos de argumentos inesperados:
EDIT: Créditos a jerone por sua
++num
idéia elegante !fonte
String.prototype.repeat = function(n){return new Array(isNaN(n) ? 1 : ++n).join(this);}
Usar
Array(N+1).join("string_to_repeat")
fonte
é assim que se repete a string várias vezes usando o delimeter.
fonte
Aqui está uma melhoria de 5-7% na resposta da disfated.
Desenrole o loop parando em
count > 1
e execute umaresult += pattnern
concat adicional após o loop. Isso evitará que os loops finais não sejam utilizados anteriormentepattern += pattern
sem a necessidade de usar uma verificação de if cara. O resultado final ficaria assim:E aqui está o violino de disfated bifurcado para a versão desenrolada: http://jsfiddle.net/wsdfg/
fonte
fonte
var r=s; for (var a=1;...
:)))) De qualquer forma, de acordo com este teste ( jsperf.com/string-repeat/2 ), fazendo um loop for simples com concatanação de strings, como o que você sugeriu parece ser muito mais rápido no Chrome, em comparação com o Array .Junte-se.Testes dos vários métodos:
fonte
Aqui está a versão segura do JSLint
fonte
Para todos os navegadores
Isso é o mais conciso possível:
Se você também se importa com o desempenho, esta é uma abordagem muito melhor:
Se você deseja comparar o desempenho de ambas as opções, consulte este Fiddle e este Fiddle para testes de benchmark. Durante meus próprios testes, a segunda opção foi cerca de 2 vezes mais rápida no Firefox e cerca de 4 vezes mais rápida no Chrome!
Apenas para navegadores modernos:
Nos navegadores modernos, agora você também pode fazer isso:
Essa opção não é apenas mais curta que as outras duas opções, mas é ainda mais rápida que a segunda opção.
Infelizmente, ele não funciona em nenhuma versão do Internet Explorer. Os números na tabela especificam a primeira versão do navegador que suporta totalmente o método:
fonte
Você pode testá-lo no JSFiddle . Comparado com o hacky
Array.join
e o meu, aproximadamente, 10 (Chrome) a 100 (Safari) e 200 (Firefox) vezes mais rápido (dependendo do navegador).fonte
Apenas outra função de repetição:
fonte
ES2015
foi 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/ String / repeat
http://www.w3schools.com/jsref/jsref_repeat.asp
fonte
Este pode ser o menor recursivo: -
fonte
Fiddle: http://jsfiddle.net/3Y9v2/
fonte
Concatenação recursiva simples
Eu só queria fazer uma festança e fiz o seguinte:
Não posso dizer que pensei muito, e provavelmente mostra :-)
Isto é sem dúvida melhor
E é como uma resposta já postada - eu sei disso.
Mas por que ser recursivo?
E que tal um pouco de comportamento padrão também?
Porque , embora o método não recursivo processe repetições arbitrariamente grandes sem atingir os limites da pilha de chamadas, é muito mais lento.
Por que me incomodei em adicionar mais métodos que não são tão inteligentes quanto os que já foram publicados?
Em parte por diversão, e em parte pela maneira mais simples: sei que existem várias maneiras de esfolar um gato e, dependendo da situação, é bem possível que o melhor método aparentemente não seja o ideal.
Um método relativamente rápido e sofisticado pode travar e queimar efetivamente sob certas circunstâncias, enquanto um método mais lento e simples pode fazer o trabalho - eventualmente.
Alguns métodos podem ser pouco mais de exploits, e, como tal, propenso a ser fixado fora da existência, e outros métodos podem funcionar muito bem em todas as condições, mas são construídos de tal modo que um simplesmente não tem idéia de como ele funciona.
"Então, e se eu não sei como isso funciona ?!"
Seriamente?
O JavaScript sofre de um dos seus maiores pontos fortes; é altamente tolerante ao mau comportamento e é tão flexível que se inclina para trás para retornar resultados, quando poderia ter sido melhor para todos se tivesse sido quebrado!
"Com grande poder, vem grande responsabilidade" ;-)
Mas, mais sério e importante, embora questões gerais como essa levem à grandiosidade na forma de respostas inteligentes que, se nada mais, expandem o conhecimento e os horizontes, no final, a tarefa em mãos - o roteiro prático que usa o método resultante - pode exigir um pouco menos, ou um pouco mais inteligente do que é sugerido.
Esses algoritmos "perfeitos" são divertidos e tudo, mas "tamanho único" raramente será melhor do que o feito sob medida.
Este sermão foi oferecido a você como cortesia da falta de sono e de um interesse passageiro. Vá em frente e codifique!
fonte
Em primeiro lugar, as perguntas do OP parecem ser concisas - o que entendo como "simples e fácil de ler", enquanto a maioria das respostas parece ser sobre eficiência - o que obviamente não é a mesma coisa e também acho que, a menos que você implemente algumas algoritmos específicos de manipulação de dados grandes, não deve se preocupar quando você implementar funções JavaScript de manipulação básica de dados. Concisão é muito mais importante.
Em segundo lugar, como observou André Laszlo, o String.repeat faz parte do ECMAScript 6 e já está disponível em várias implementações populares - portanto, a implementação mais concisa
String.repeat
é não implementá-lo ;-)Por fim, se você precisar oferecer suporte a hosts que não oferecem a implementação do ECMAScript 6, o polyfill do MDN mencionado por André Laszlo é tudo menos conciso.
Portanto, sem mais delongas - aqui está o meu polyfill conciso :
Sim, isso é uma recursão. Eu gosto de recursões - elas são simples e, se feitas corretamente, são fáceis de entender. Em relação à eficiência, se o idioma suportar, eles podem ser muito eficientes se escritos corretamente.
Dos meus testes, esse método é ~ 60% mais rápido que a
Array.join
abordagem. Embora, obviamente, não chegue nem perto da implementação do desatualizado, é muito mais simples que os dois.Minha configuração de teste é o nó v0.10, usando o "Modo estrito" (acho que permite algum tipo de TCO ), chamando
repeat(1000)
uma sequência de 10 caracteres um milhão de vezes.fonte
Se você acha que todas essas definições de protótipos, criações de matriz e operações de junção são um exagero, basta usar um código de linha único onde for necessário. Sequência S repetindo N vezes:
fonte
Array(N + 1).join(str)
método se não houver um gargalo de desempenho). Se houver a menor chance de usá-lo duas vezes, mova-o para uma função de nome apropriado.Use a funcionalidade do utilitário Lodash para Javascript, como repetir strings.
O Lodash oferece bom desempenho e compatibilidade com ECMAScript.
Eu o recomendo para o desenvolvimento da interface do usuário e também funciona bem no servidor.
Veja como repetir a string "yo" 2 vezes usando o Lodash:
fonte
Solução recursiva usando dividir e conquistar:
fonte
Eu vim aqui aleatoriamente e nunca tive um motivo para repetir um caractere em javascript antes.
Fiquei impressionado com a maneira de fazer isso da artistoex e com os resultados desatualizados. Notei que o último concat de cordas era desnecessário, como Dennis também apontou.
Notei mais algumas coisas ao brincar com a amostra desfeita reunida.
Os resultados variaram bastante, favorecendo a última corrida, e algoritmos similares frequentemente disputavam posição. Uma das coisas que mudei foi em vez de usar a contagem gerada pelo JSLitmus como a semente das chamadas; como a contagem foi gerada diferente para os vários métodos, coloquei um índice. Isso tornou a coisa muito mais confiável. Eu, então, olhei para garantir que seqüências de tamanhos variadas fossem passadas para as funções. Isso impediu algumas das variações que eu vi, onde alguns algoritmos se saíram melhor nos caracteres únicos ou nas seqüências menores. No entanto, os três métodos principais foram bem, independentemente do tamanho da string.
Conjunto de teste bifurcado
http://jsfiddle.net/schmide/fCqp3/134/
Eu então incluí a correção de Dennis e decidi ver se eu poderia encontrar uma maneira de me aprofundar um pouco mais.
Como o javascript não pode realmente otimizar as coisas, a melhor maneira de melhorar o desempenho é evitar as coisas manualmente. Se eu tirasse os 4 primeiros resultados triviais do loop, poderia evitar de 2 a 4 armazenamentos de string e gravar o armazenamento final diretamente no resultado.
Isso resultou em uma melhoria de 1-2%, em média, em relação à correção de Dennis. No entanto, diferentes execuções e navegadores diferentes mostrariam uma variação suficiente o suficiente para que esse código extra provavelmente não valha o esforço dos 2 algoritmos anteriores.
Um gráfico
Edit: Eu fiz isso principalmente no chrome. O Firefox e o IE costumam favorecer Dennis em alguns%.
fonte
Método simples:
fonte
As pessoas complicam demais isso de maneira ridícula ou perdem desempenho. Matrizes? Recursão? Só podes estar a brincar comigo.
Editar. Fiz alguns testes simples para comparar com a versão bit a bit postada por artistoex / disfated e várias outras pessoas. O último foi apenas um pouco mais rápido, mas ordens de magnitude mais eficientes em termos de memória. Para 1000000 repetições da palavra 'blah', o processo Node subiu para 46 megabytes com o algoritmo de concatenação simples (acima), mas apenas 5,5 megabytes com o algoritmo logarítmico. Este último é definitivamente o caminho a percorrer. Reposicionando-o por uma questão de clareza:
fonte
string += string
metade redundante do tempo.Concatenando cadeias com base em um número.
Espero que ajude!
fonte
Com o ES8, você também pode usar
padStart
oupadEnd
para isso. por exemplo.fonte