What is the best or most concise method for returning a string repeated an arbitrary amount of times?
The following is my best shot so far:
function
Just another repeat function:
function repeat(s, n) {
var str = '';
for (var i = 0; i < n; i++) {
str += s;
}
return str;
}
I just wanted to give it a bash, and made this:
function ditto( s, r, c ) {
return c-- ? ditto( s, r += s, c ) : r;
}
ditto( "foo", "", 128 );
I can't say I gave it much thought, and it probably shows :-)
String.prototype.ditto = function( c ) {
return --c ? this + this.ditto( c ) : this;
};
"foo".ditto( 128 );
And it's a lot like an answer already posted - I know this.
And how about a little default behaviour too?
String.prototype.ditto = function() {
var c = Number( arguments[ 0 ] ) || 2,
r = this.valueOf();
while ( --c ) {
r += this;
}
return r;
}
"foo".ditto();
Because, although the non recursive method will handle arbitrarily large repeats without hitting call stack limits, it's a lot slower.
Partly for my own amusement, and partly to point out in the simplest way I know that there are many ways to skin a cat, and depending on the situation, it's quite possible that the apparently best method isn't ideal.
A relatively fast and sophisticated method may effectively crash and burn under certain circumstances, whilst a slower, simpler method may get the job done - eventually.
Some methods may be little more than exploits, and as such prone to being fixed out of existence, and other methods may work beautifully in all conditions, but are so constructed that one simply has no idea how it works.
"So what if I dunno how it works?!"
Seriously?
JavaScript suffers from one of its greatest strengths; it's highly tolerant of bad behaviour, and so flexible it'll bend over backwards to return results, when it might have been better for everyone if it'd snapped!
"With great power, comes great responsibility" ;-)
But more seriously and importantly, although general questions like this do lead to awesomeness in the form of clever answers that if nothing else, expand one's knowledge and horizons, in the end, the task at hand - the practical script that uses the resulting method - may require a little less, or a little more clever than is suggested.
These "perfect" algorithms are fun and all, but "one size fits all" will rarely if ever be better than tailor made.
This sermon was brought to you courtesy of a lack of sleep and a passing interest. Go forth and code!
I've tested the performance of all the proposed approaches.
Here is the fastest variant I've got.
String.prototype.repeat = function(count) {
if (count < 1) return '';
var result = '', pattern = this.valueOf();
while (count > 1) {
if (count & 1) result += pattern;
count >>= 1, pattern += pattern;
}
return result + pattern;
};
Or as stand-alone function:
function repeat(pattern, count) {
if (count < 1) return '';
var result = '';
while (count > 1) {
if (count & 1) result += pattern;
count >>= 1, pattern += pattern;
}
return result + pattern;
}
It is based on artistoex algorithm.
It is really fast. And the bigger the count
, the faster it goes compared with the traditional new Array(count + 1).join(string)
approach.
I've only changed 2 things:
pattern = this
with pattern = this.valueOf()
(clears one obvious type conversion);if (count < 1)
check from prototypejs to the top of function to exclude unnecessary actions in that case.UPD
Created a little performance-testing playground here for those who interested.
variable count
~ 0 .. 100:
constant count
= 1024:
Use it and make it even faster if you can :)
Firstly, the OP's questions seems to be about conciseness - which I understand to mean "simple and easy to read", while most answers seem to be about efficiency - which is obviously not the same thing and also I think that unless you implement some very specific large data manipulating algorithms, shouldn't worry you when you come to implement basic data manipulation Javascript functions. Conciseness is much more important.
Secondly, as André Laszlo noted, String.repeat is part of ECMAScript 6 and already available in several popular implementations - so the most concise implementation of String.repeat
is not to implement it ;-)
Lastly, if you need to support hosts that don't offer the ECMAScript 6 implementation, MDN's polyfill mentioned by André Laszlo is anything but concise.
So, without further ado - here is my concise polyfill:
String.prototype.repeat = String.prototype.repeat || function(n){
return n<=1 ? this : this.concat(this.repeat(n-1));
}
Yes, this is a recursion. I like recursions - they are simple and if done correctly are easy to understand. Regarding efficiency, if the language supports it they can be very efficient if written correctly.
From my tests, this method is ~60% faster than the Array.join
approach. Although it obviously comes nowhere close disfated's implementation, it is much simpler than both.
My test setup is node v0.10, using "Strict mode" (I think it enables some sort of TCO), calling repeat(1000)
on a 10 character string a million times.
If you think all those prototype definitions, array creations, and join operations are overkill, just use a single line code where you need it. String S repeating N times:
for (var i = 0, result = ''; i < N; i++) result += S;
Use Array(N+1).join("string_to_repeat")