Повторите строку - Javascript - PullRequest
       97

Повторите строку - Javascript

264 голосов
/ 15 октября 2008

Каков наилучший или самый краткий метод для возврата строки, повторенной произвольное количество раз?

На данный момент мой лучший снимок:

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

Ответы [ 29 ]

1 голос
/ 18 декабря 2014

Во-первых, вопросы ОП, кажется, касаются краткости - которую я понимаю, что означает «простой и легкий для чтения», в то время как большинство ответов, похоже, касаются эффективности - что, очевидно, не одно и то же, и я думаю, что если вы не Реализуйте некоторые очень специфические алгоритмы манипулирования большими данными, не стоит беспокоиться, когда вы приступаете к реализации базовых функций обработки данных Javascript. Краткость гораздо важнее.

Во-вторых, как отметил Андре Ласло, String.repeat является частью ECMAScript 6 и уже доступен в нескольких популярных реализациях, поэтому самая краткая реализация String.repeat - это не его реализация; -)

Наконец, если вам нужно поддерживать хосты, которые не предлагают реализацию ECMAScript 6, полифил MDN, упомянутый Андре Ласло, совсем не лаконичен.

Итак, без лишних слов - вот мой краткий polyfill:

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

Да, это рекурсия. Мне нравятся рекурсии - они просты, и если все сделано правильно, их легко понять. Что касается эффективности, если язык поддерживает ее, они могут быть очень эффективными, если написаны правильно.

Из моих тестов этот метод на ~ 60% быстрее, чем Array.join. Хотя это явно нигде не соответствует реализации disfated, это гораздо проще, чем оба.

Моя тестовая установка - это узел v0.10, использующий «Строгий режим» (я думаю, что он разрешает какой-то TCO ), вызывая repeat(1000) для строки из 10 символов миллион раз.

1 голос
/ 17 октября 2014

Простая рекурсивная конкатенация

Я просто хотел сделать удар и сделал это:

function ditto( s, r, c ) {
    return c-- ? ditto( s, r += s, c ) : r;
}

ditto( "foo", "", 128 );

Не могу сказать, что много думал об этом, и это, вероятно, показывает: -)

Это возможно лучше

String.prototype.ditto = function( c ) {
    return --c ? this + this.ditto( c ) : this;
};

"foo".ditto( 128 );

И это очень похоже на уже опубликованный ответ - я знаю это.

Но зачем вообще быть рекурсивным?

А как насчет небольшого поведения по умолчанию?

String.prototype.ditto = function() {
    var c = Number( arguments[ 0 ] ) || 2,
        r = this.valueOf();
    while ( --c ) {
        r += this;
    }
    return r;
}

"foo".ditto();

Поскольку , хотя нерекурсивный метод будет обрабатывать произвольно большие повторы, не выходя за пределы стека вызовов, он намного медленнее.

Почему я удосужился добавить больше методов, которые не настолько наполовину такие же умные , как те, которые уже опубликованы? Отчасти для собственного удовольствия, а отчасти, чтобы показать самым простым способом, я знаю, что существует множество способов снятия шкуры с кошки, и, в зависимости от ситуации, вполне возможно, что, по-видимому, лучший метод не идеально. Относительно быстрый и сложный метод может эффективно привести к сбою и сбою при определенных обстоятельствах, в то время как более медленный и простой метод может выполнить работу - в конечном итоге. Некоторые методы могут быть немного больше, чем эксплойты, и как таковые могут быть фиксированными из существования, а другие методы могут прекрасно работать в любых условиях, но сконструированы так, что one просто понятия не имеет, как это работает. «А что, если я не знаю, как это работает?!» Серьезно? JavaScript обладает одной из самых сильных сторон; он очень терпим к плохому поведению и настолько гибок, что будет изгибаться назад, чтобы возвращать результаты, когда это могло бы быть лучше для всех, если бы оно сломалось! «С великой силой приходит большая ответственность» ; -) Но более серьезно и важно то, что общие вопросы, подобные этому, приводят к удивительности в виде умных ответов, которые, если не что иное, расширяют свои знания и горизонты, в конце концов, стоящая перед нами задача - практический сценарий, который использует полученный метод - может потребовать немного меньше или чуть больше умного , чем предлагается. Эти «совершенные» алгоритмы - это весело и все, но «один размер подходит всем» редко, если вообще когда-либо, лучше, чем сделанные на заказ. Эта проповедь была принесена вам из-за недостатка сна и преходящего интереса. Идите вперед и код!

1 голос
/ 05 августа 2014

Скрипка: http://jsfiddle.net/3Y9v2/

function repeat(s, n){
    return ((new Array(n+1)).join(s));
}
alert(repeat('R', 10));
0 голосов
/ 02 мая 2019

С ES8 вы также можете использовать padStart или padEnd для этого. например.

var str = 'cat';
var num = 23;
var size = str.length * num;
"".padStart(size, str) // outputs: 'catcatcatcatcatcatcatcatcatcatcatcatcatcatcatcatcatcatcatcatcatcatcat'
0 голосов
/ 17 апреля 2016

Объединение строк на основе числа.

function concatStr(str, num) {
   var arr = [];

   //Construct an array
   for (var i = 0; i < num; i++)
      arr[i] = str;

   //Join all elements
   str = arr.join('');

   return str;
}

console.log(concatStr("abc", 3));

Надеюсь, это поможет!

0 голосов
/ 04 октября 2011

Рекурсивное решение с использованием разделяй и властвуй:

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); }
}
0 голосов
/ 31 августа 2014

Люди слишком усложняют это до абсурдной или бесполезной производительности. Массивы? Рекурсия? Ты, должно быть, шутишь.

function repeat (string, times) {
  var result = ''
  while (times-- > 0) result += string
  return result
}

Редактировать. Я провел несколько простых тестов, чтобы сравнить их с побитовой версией, опубликованной artistoex / disfated и группой других людей. Последний был лишь незначительно быстрее, но на несколько порядков эффективнее с точки зрения памяти. Для 1000000 повторений слова «бла» процесс Node достигал 46 мегабайт с помощью простого алгоритма конкатенации (см. Выше), но только 5,5 мегабайт с логарифмическим алгоритмом. Последний, безусловно, путь. Репост для ясности:

function repeat (string, times) {
  var result = ''
  while (times > 0) {
    if (times & 1) result += string
    times >>= 1
    string += string
  }
  return result
}
0 голосов
/ 15 марта 2013

Я пришел сюда случайно, и у меня никогда не было причин повторять символ в javascript.

Я был впечатлен тем, как artistoex сделал это, и разочаровал результаты. Я заметил, что последняя строка в concat не нужна, как указал Деннис.

Я заметил еще несколько вещей, когда играл с разбитым семплом.

Результаты варьировались в достаточной степени, часто в пользу последнего запуска, и подобные алгоритмы часто приводили в замешательство позицию. Одна из вещей, которые я изменил, была вместо того, чтобы использовать сгенерированный JSLitmus счет в качестве начального числа для вызовов; так как счетчик был сгенерирован по-разному для различных методов, я поместил в индекс. Это сделало вещь намного более надежной. Затем я посмотрел, чтобы в функции передавались строки разного размера. Это предотвратило некоторые изменения, которые я видел, когда некоторые алгоритмы работали лучше в одиночных символах или меньших строках. Тем не менее, лучшие 3 метода все хорошо, независимо от размера строки.

Вилочный тестовый набор

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();

Затем я включил исправление Денниса и решил посмотреть, смогу ли я найти способ получить больше.

Поскольку javascript не может реально оптимизировать вещи, лучший способ повысить производительность - это избегать вещей вручную. Если бы я вынул первые 4 тривиальных результата из цикла, я мог бы избежать 2-4 хранилищ строк и записать окончательное хранилище непосредственно в результат.

// 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;
}

Это привело к улучшению на 1-2% по сравнению с исправлением Денниса. Тем не менее, различные прогоны и разные браузеры будут демонстрировать достаточно справедливую дисперсию, что этот дополнительный код, вероятно, не стоит усилий по сравнению с двумя предыдущими алгоритмами.

График

Редактировать: Я делал это в основном под Chrome. Firefox и IE часто предпочитают Денниса на пару%.

0 голосов
/ 29 мая 2013

Простой метод:

String.prototype.repeat = function(num) {
    num = parseInt(num);
    if (num < 0) return '';
    return new Array(num + 1).join(this);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...