275 votes

Chaîne de répétition - Javascript

Quelle est la méthode la plus efficace ou la plus concise pour renvoyer une chaîne de caractères répétée un nombre arbitraire de fois ?

Ce qui suit est mon meilleur essai jusqu'à présent :

function repeat(s, n){
    var a = [];
    while(a.length < n){
        a.push(s);
    }
    return a.join('');
}

5 votes

Il y a plus de 10 ans, j'ai trouvé une solution bien connue à ce problème, que j'ai utilisée comme exemple dans un article sur l'optimisation du JavaScript quelques mois avant que vous ne posiez cette question : webreference.com/programmation/javascript/jkm3/3.html Apparemment, la plupart des gens ont oublié ce code, et je ne vois pas de solution aussi bonne que la mienne. Le meilleur algorithme semble avoir été repris de mon code ; sauf qu'en raison d'une mauvaise compréhension du fonctionnement de mon code, il effectue une étape supplémentaire de concaténation exponentielle qui est éliminée dans mon code original par une boucle spéciale.

0 votes

Veuillez essayer cette comparaison et envisager de remplacer la réponse acceptée par la solution de longue date à ce problème, publiée avant même que cette question ne soit posée. jsperf.com/repeating-strings

11 votes

Personne n'a levé la solution de Joseph. L'algorithme a 3700 ans. Le coût de cette étape supplémentaire est négligeable. En outre, le coût de l'étape supplémentaire est négligeable. cet article contient des erreurs et des idées fausses concernant la concaténation de chaînes de caractères en Javascript. Pour toute personne intéressée par la manière dont Javascript gère réellement les chaînes de caractères en interne, voir Corde .

2voto

Guss Points 6512

Tout d'abord, la question de l'OP semble porter sur la concision - que je comprends comme "simple et facile à lire", alors que la plupart des réponses semblent porter sur l'efficacité - ce qui n'est évidemment pas la même chose et aussi je pense qu'à moins que vous ne mettiez en œuvre des algorithmes très spécifiques de manipulation de grandes données, vous ne devriez pas vous inquiéter lorsque vous en arrivez à mettre en œuvre des fonctions Javascript de manipulation de données de base. La concision est bien plus importante.

Deuxièmement, comme l'a fait remarquer André Laszlo, String.repeat fait partie de l'ECMAScript 6 et est déjà disponible dans plusieurs implémentations populaires - ainsi, l'implémentation la plus concise de String.repeat est de ne pas la mettre en œuvre ;-)

Enfin, si vous devez prendre en charge des hôtes qui ne proposent pas l'implémentation ECMAScript 6, la polyfill de MDN mentionnée par André Laszlo est tout sauf concise.

Alors, sans plus attendre, voici ma concis polyfill :

String.prototype.repeat = String.prototype.repeat || function(n){
    return n<=1 ? this : this.concat(this.repeat(n-1));
}

Oui, il s'agit d'une récursion. J'aime les récursions - elles sont simples et, si elles sont faites correctement, elles sont faciles à comprendre. En ce qui concerne l'efficacité, si le langage le permet, elles peuvent être très efficaces si elles sont écrites correctement.

D'après mes tests, cette méthode est ~60% plus rapide que la méthode Array.join l'approche. Bien qu'elle soit loin de s'approcher de la mise en œuvre de disfated, elle est beaucoup plus simple que les deux.

Ma configuration de test est node v0.10, utilisant le "Strict mode" (je pense qu'il permet une sorte de "Strict mode") et le "Strict mode" (je pense que cela permet une sorte de "Strict mode"). TCO ), en appelant repeat(1000) sur une chaîne de 10 caractères un million de fois.

2voto

l3x Points 434

Utilisez Lodash pour les fonctionnalités utilitaires de Javascript, comme la répétition de chaînes de caractères.

Lodash offre de bonnes performances et une compatibilité ECMAScript.

Je le recommande vivement pour le développement de l'interface utilisateur et il fonctionne également très bien côté serveur.

Voici comment répéter la chaîne "yo" 2 fois en utilisant Lodash :

> _.repeat('yo', 2)
"yoyo"

1voto

Fordi Points 917

Solution récursive utilisant la méthode "diviser pour régner" :

function repeat(n, s) {
    if (n==0) return '';
    if (n==1 || isNaN(n)) return s;
    with(Math) { return repeat(floor(n/2), s)+repeat(ceil(n/2), s); }
}

1voto

Je suis venu ici par hasard et je n'ai jamais eu de raison de répéter un caractère en javascript auparavant.

J'ai été impressionné par la façon de procéder d'artistoex et par les résultats de disfated. J'ai remarqué que la dernière concaténation de chaîne n'était pas nécessaire, comme Dennis l'a également souligné.

J'ai remarqué d'autres choses en jouant avec l'ensemble de l'échantillonnage.

Les résultats variaient considérablement, favorisant souvent la dernière course et des algorithmes similaires se disputaient souvent la position. L'une des choses que j'ai changées, c'est qu'au lieu d'utiliser le décompte généré par JSLitmus comme semence pour les appels, comme le décompte était généré différemment pour les diverses méthodes, j'ai mis un index. Cela a rendu la chose beaucoup plus fiable. J'ai ensuite cherché à m'assurer que des chaînes de taille variable étaient transmises aux fonctions. Cela a permis d'éviter certaines des variations que j'avais observées, où certains algorithmes étaient plus performants avec des caractères uniques ou des chaînes plus petites. Cependant, les trois méthodes les plus performantes ont toutes obtenu de bons résultats, quelle que soit la taille de la chaîne.

Ensemble de tests bifurqués

http://jsfiddle.net/schmide/fCqp3/134/

// repeated string
var string = '0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789';
// count paremeter is changed on every test iteration, limit it's maximum value here
var maxCount = 200;

var n = 0;
$.each(tests, function (name) {
    var fn = tests[name];
    JSLitmus.test(++n + '. ' + name, function (count) {
        var index = 0;
        while (count--) {
            fn.call(string.slice(0, index % string.length), index % maxCount);
            index++;
        }
    });
    if (fn.call('>', 10).length !== 10) $('body').prepend('<h1>Error in "' + name + '"</h1>');
});

JSLitmus.runAll();

J'ai ensuite inclus la solution de Dennis et j'ai décidé de voir si je pouvais trouver un moyen de gagner un peu plus.

Comme le javascript ne peut pas vraiment optimiser les choses, la meilleure façon d'améliorer les performances est d'éviter manuellement certaines choses. Si je retirais les 4 premiers résultats triviaux de la boucle, je pourrais éviter 2 à 4 chaînes de caractères et écrire la dernière chaîne directement dans le résultat.

// final: growing pattern + prototypejs check (count < 1)
'final avoid': function (count) {
    if (!count) return '';
    if (count == 1) return this.valueOf();
    var pattern = this.valueOf();
    if (count == 2) return pattern + pattern;
    if (count == 3) return pattern + pattern + pattern;
    var result;
    if (count & 1) result = pattern;
    else result = '';
    count >>= 1;
    do {
        pattern += pattern;
        if (count & 1) result += pattern;
        count >>= 1;
    } while (count > 1);
    return result + pattern + pattern;
}

Cela s'est traduit par une amélioration de 1 à 2 % en moyenne par rapport à la solution de Dennis. Cependant, des exécutions différentes et des navigateurs différents montreraient une variance assez importante pour que ce code supplémentaire ne vaille probablement pas la peine d'être utilisé par rapport aux deux algorithmes précédents.

Un tableau

Edit : J'ai fait cela principalement sous chrome. Firefox et IE favorisent souvent Dennis de quelques %.

1voto

Eduardo Cuomo Points 1433

Méthode simple :

String.prototype.repeat = function(num) {
    num = parseInt(num);
    if (num < 0) return '';
    return new Array(num + 1).join(this);
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X