Simple way to repeat a string
Asked Answered
L

33

793

I'm looking for a simple commons method or operator that allows me to repeat some string n times. I know I could write this using a for loop, but I wish to avoid for loops whenever necessary and a simple direct method should exist somewhere.

String str = "abc";
String repeated = str.repeat(3);

repeated.equals("abcabcabc");

Related to:

repeat string javascript Create NSString by repeating another string a given number of times

Edited

I try to avoid for loops when they are not completely necessary because:

  1. They add to the number of lines of code even if they are tucked away in another function.

  2. Someone reading my code has to figure out what I am doing in that for loop. Even if it is commented and has meaningful variables names, they still have to make sure it is not doing anything "clever".

  3. Programmers love to put clever things in for loops, even if I write it to "only do what it is intended to do", that does not preclude someone coming along and adding some additional clever "fix".

  4. They are very often easy to get wrong. For loops involving indexes tend to generate off by one bugs.

  5. For loops often reuse the same variables, increasing the chance of really hard to find scoping bugs.

  6. For loops increase the number of places a bug hunter has to look.

Lafrance answered 5/8, 2009 at 19:14 Comment(18)
I understand that for loops can cause some real issues. But you shouldn't try to avoid for loops "at all costs" because if it costs you readability, maintainability, and speed, you're being counterproductive. This is one of those cases.Nicely
With those concerns, consider having exhaustive unittests for your code. This allows you to just show the unit test when documentation is needed.Volscian
"They add to the number of lines of code even if they are tucked away in another function"...wow, just wow. Big-O, not LoCFrampton
@imagist I'm avoiding for loops in situations where it costs me readability, and maintainability. I consider speed as the least important issue here (a non-issue in fact). I think for loops are overused and I am trying to learn to only use for loops when they are necessary and not as a default solution.Lafrance
@Frampton I'm not claiming performance or asymptotic benefits. Rather saying that by writing less code, and using library functions rather than reinventing the wheel I reduce the bug surface area(Lines of Code) while increasing readability. Both good things I'm sure you'll agree.Lafrance
@e5: Those are good things, but they don't always follow from using library functions. What people are saying to you is that inappropriate use of library functions (e.g. "avoiding loops at all costs") can decrease readability, increase bug surface area [*], and make your application catastrophically slower. [ Libraries can have bugs too!]Zia
@Stephen C , Oh certainly, I completely agree with thing you just said! When I say "avoid loops at all costs", I'm exaggerating my position a bit for dramatic effect. For loops are necessary and good, but I do see an overuse of them in my code and others. I am merely trying to improve my style.Lafrance
@e5;sorry for posting years later.I find this question so appropriate. If inserted in a method, arguments should be tested (times>=0), errors thrown etc.This adds robustness but also lines of code to read. Repeating a string is something unambiguous.Who reads the code knows exactly what a string.repeat does, even without a line of comment or javadoc.If we use a stable library, is reasonable to think that a so-simple function has no bugs,YET introduces some form of "robustness" check that we even need to worry about.If i could ask 10 improvements, this (kind of) things would be one.Zampino
@Zampino Looking back at this question I realize one more problem with for loops. They specify the order in which actions must be performed when most of the time the engineer only wants to perform some action on every element in a list (regardless of order). This order dependency makes it much harder for compilers to parallelize code. I think the python map function has the right of it: docs.python.org/library/functions.html#mapLafrance
@Zampino Raises pitchfork in total agreement. "Death to the for loop, long live readability"!Lafrance
@e5:another good reason to avoid loops is that java has already introduced iterators with the sole scope of alleviate the loops declaration.There has been such an heavy effort to that purpose.Improving the String API a bit would allow for the complete elimination of "obvious" loops from code at a very low cost.And a much greater (yet understimated) benefit.The time it takes to understand the simplest loop is much greater than the time spent in reading "repeat" word. String[] x = {"think?", "you", "dont"}; for (int i=x.length-1;i>=0;i--) { System.out.println(x[i]); }Zampino
@e5: the order question is correct but I think that you cannot turn a procedural language into a declarative one "just in case". I don't know if you feel so relaxed when iterating collection items and deleting some of them because "you only want to perform an action on each element" leaving to the library implementation "not to do a mess". Perhaps you would study the API more in deep. If you had not time, you probably choose a fail-proof procedural approach like a downto-removal :-)Zampino
@e5: however, i think that several of these reasons are pretty "strict". perhaps enough to start a JCP request. wouldn't it be wonderful?Zampino
"Clever" code should be avoided. for loops should not. Make the code do what it looks like, and use many lines if needed. Your compiler will make it all small and clever - out of sight.Commitment
@Commitment "Clever" code should be avoided, I agree. But for-loops are "clever" code you have just become used to them. Consider that the for-loop relies on a mathematical relationship between how we store strings in arrays (a fairly arbitrary, machine dependent choice) and a periodically increasing integer. Before you disagree try explaining how you would 'repeat a string using for-loops' to a non-programmer.Lafrance
@EthanHeilman here goes: "we store the string as a list of characters, each in a numbered box. If I need a string that is 100 long, I first put a character in box 1, then box 2, all the way until I get to box 100. Then I stop adding characters. " That seems to describe the for loop quite well. I decided not to explain the "zero offset" since that is irrelevant to the explanation to the non-programmer.Commitment
If you're on Java 11, you can use String::repeat - see this answer.Plectron
repeats = "abc" * 3 Python is much more condensed than javaPostfree
P
401

String::repeat

". ".repeat(7)  // Seven period-with-space pairs: . . . . . . . 

New in Java 11 is the method String::repeat that does exactly what you asked for:

String str = "abc";
String repeated = str.repeat(3);
repeated.equals("abcabcabc");

Its Javadoc says:

/**
 * Returns a string whose value is the concatenation of this
 * string repeated {@code count} times.
 * <p>
 * If this string is empty or count is zero then the empty
 * string is returned.
 *
 * @param count number of times to repeat
 *
 * @return A string composed of this string repeated
 * {@code count} times or the empty string if this
 * string is empty or count is zero
 *
 * @throws IllegalArgumentException if the {@code count} is
 * negative.
 *
 * @since 11
 */ 
Plectron answered 2/3, 2018 at 8:31 Comment(3)
@Nicolai source code for it, just in case someone cares hg.openjdk.java.net/jdk/jdk/file/fc16b5f193c7/src/java.base/…Basilio
i have not even seen java 9 yet on the street (and will not for a long time..) - and 11 is apparently set to ship..Topping
Probably obvious, but you can call this method on a string literal too: "abc".repeat(3)Nay
M
1014

Here is the shortest version (Java 1.5+ required):

repeated = new String(new char[n]).replace("\0", s);

Where n is the number of times you want to repeat the string and s is the string to repeat.

No imports or libraries needed.

Muchness answered 4/2, 2011 at 22:34 Comment(12)
I don't think it's obfuscated at all. Primitive types (char[], in this case) are instantiated with nulls, then a String is created from the char[], and the nulls are replaced() with the character you want in sBibliopole
While this is very clever (+1) I think it pretty much proves the point that for loops often make for clearer codeNoisy
To those who complain about obfuscation, readability depends on literacy. This is perfectly clear in what it does and educational for those who may not see it right away. This is what you get with Java by the way.Ergener
This should really be marked as the answer. When your looking for a 'simple' solution, including external libraries should really be a last resort if a better alternative exists. And this is a very very good alternative.Chisholm
For better performance ...replace('\0', str) should be used instead of the String version.Polarize
@user686249: There are only replace(char oldChar, char newChar) and replace(CharSequence target, CharSequence replacement) so I don't see how that could workMuchness
@fortran I'm sorry for that mistake..... this should work Integer.toString(Math.pow(10, n)).replace("1", "").replace("0", str); or this Integer.toBinaryString(Math.pow(2, n)).replace("1", "").replace("0", str); DON'T use this for large number lolChemmy
I needed to use replaceAll() to make it work, and it's 10 times slower than a new StringBuilder(length) and a while(repeat-- > 0) { sb.apend(word)}Ducky
So the \0 end of string delimiter was resurrected from C ? What are other useful applications of it in java ?Topping
@javadba: No, this has nothing to do with "end of string delimiters" (which don't exist here anyway). Rather, when you create a new array, all elements are initialized to the zero value of the type; in the case of char, that's the 0 character. We simply do a replacement on each occurrence of that character.Muchness
@Muchness To be precise: it's the null character, not "the 0 [zero] character".Slippage
@Caner answer is readable: String.join("", Collections.nCopies(n, s)); #1235679Behre
R
573

If you are using Java <= 7, this is as "concise" as it gets:

// create a string made up of n copies of string s
String.format("%0" + n + "d", 0).replace("0", s);

In Java 8 and above there is a more readable way:

// create a string made up of n copies of string s
String.join("", Collections.nCopies(n, s));

Finally, for Java 11 and above, there is a new repeat​(int count) method specifically for this purpose(link)

"abc".repeat(12);

Alternatively, if your project uses java libraries there are more options.

For Apache Commons:

StringUtils.repeat("abc", 12);

For Google Guava:

Strings.repeat("abc", 12);
Rochelrochell answered 28/7, 2011 at 11:5 Comment(6)
The former causes an exception when n is zero.Sophomore
The java 8 example does not compile -> Type mismatch: cannot convert from List<Character> to CharSequenceSupertonic
@Supertonic s has to be String, not a CharRochelrochell
@Rochelrochell Thanks. My bad, I apologize. Apparently I was too tired yesterday. Sorry about downvoting. I'll remove the downvote as soon as I could (it's blocked until question is edited)Supertonic
@Supertonic no problem, made it clear now that s is a stringRochelrochell
For anyone curious, the new "blah".repeat(10) in >=Java 11 appears to be very efficient, allocating byte arrays directly much like StringBuilder. Probably the best way to repeat strings from here on out!Sites
P
401

String::repeat

". ".repeat(7)  // Seven period-with-space pairs: . . . . . . . 

New in Java 11 is the method String::repeat that does exactly what you asked for:

String str = "abc";
String repeated = str.repeat(3);
repeated.equals("abcabcabc");

Its Javadoc says:

/**
 * Returns a string whose value is the concatenation of this
 * string repeated {@code count} times.
 * <p>
 * If this string is empty or count is zero then the empty
 * string is returned.
 *
 * @param count number of times to repeat
 *
 * @return A string composed of this string repeated
 * {@code count} times or the empty string if this
 * string is empty or count is zero
 *
 * @throws IllegalArgumentException if the {@code count} is
 * negative.
 *
 * @since 11
 */ 
Plectron answered 2/3, 2018 at 8:31 Comment(3)
@Nicolai source code for it, just in case someone cares hg.openjdk.java.net/jdk/jdk/file/fc16b5f193c7/src/java.base/…Basilio
i have not even seen java 9 yet on the street (and will not for a long time..) - and 11 is apparently set to ship..Topping
Probably obvious, but you can call this method on a string literal too: "abc".repeat(3)Nay
L
324

Commons Lang StringUtils.repeat()

Usage:

String str = "abc";
String repeated = StringUtils.repeat(str, 3);

repeated.equals("abcabcabc");
Litigable answered 5/8, 2009 at 19:16 Comment(14)
using a one-method-dependency for the simplicity's sake in the long run can resulting in a jar-hellRajput
Sure, except it's commons lang. I don't think I've ever seen a project over 5000 LOCS that didn't have commons lang.Lafrance
The solution to jar-hell is a managed build depency system such as maven. Import away.Verda
What makes you think that this doesn't simply tuck the for loop away in another function? (Criticism 1)Nicely
Commons Lang is open source - download it and take a look. Of course it has a loop inside, but it's not quite as simple. A lot of effort went into profiling and optimizing that implementation.Litigable
I don't avoid loops for performance reason (read my reasons in the question). When someone sees StringUtils.repeat, they know what I am doing. They don't have to worry that I attempted to write my own version of repeat and made a mistake. It is an atomic cognitive unit!Lafrance
Migrate to Maven to avoid a for-loop?? Interesting turn this is taking.Volscian
@Thorbjørn Ravn Andersen - it can get a LOT more interesting if things keep being taken out of contextLitigable
@e5 - The use and reuse of the commons classes, StringUtils especially, reduces maintenence load in a number of ways. Simple, descriptive method names, sensible defaults and null handlings and a stable codebase all make it easier to identfy where bugs are more likely to reside. One idiom I encourage is that loop control always uses "i"; this forces only one loop per method, which means the common problem of incrementing the wrong thing is removed.Unders
@Michael Rutherfurd, those are rules to live by! I've been following the "one for loop per method rule" for a few months now and it has improved the quality and readability of my code dramatically. Have trouble obeying "one for loop per method" when I'm taking the Cartesian product of two arrays. I should post a question on how to do that better. Java should to add the warning 'consider using stringUtils'.Lafrance
The Apache commons repeat uses StringBuffer internally. This will have some overhead in synchronization over your rolling your own implmementation that makes use of StringBuilder.Ampersand
@Ampersand I hadn't heard that, can you provide a link to back this up?Lafrance
Synchronization of what? StringUtils.repeat() is a static method using internal StringBuffer.Litigable
As soon as you use a framework or tool the Apache Commons will be in your project. I bet we already have StringUtils in our projects.Ploch
N
151

Java 8's String.join provides a tidy way to do this in conjunction with Collections.nCopies:

// say hello 100 times
System.out.println(String.join("", Collections.nCopies(100, "hello")));
Nay answered 25/7, 2014 at 0:17 Comment(4)
thank you! For android TextUtils.join() can be used instead of String.join()Lally
Thank you for this answer. It's seems to be the cleanest way without using any external API oder utility method! very good!!Student
The nice thing about this method is that with join you can provide a separator character which works out to be very handy if you are, say, building up a CSV list. With all the other methods you have a terminating joining character that needs to be stripped out in a separate operation.Forbear
this is a nice readable answer, but just for context (from a naive benchmark) it's 3-4x slower than just a for loop over a StringBuilder, i.e., StringBuilder sb = new StringBuilder(); for (int i = 0; i < 100; i++) { sb.append("hello"); } return sb.toString();Plater
M
104

Here's a way to do it using only standard String functions and no explicit loops:

// create a string made up of  n  copies of  s
repeated = String.format(String.format("%%%ds", n), " ").replace(" ",s);
Morgun answered 22/8, 2009 at 18:5 Comment(6)
Amazing :-) Although beware of n becoming zero…!Andrews
java.sun.com/j2se/1.4.2/docs/api/java/lang/… - replace() accepts two char parameters. Not Strings!Scurrility
I think he meant replaceAllPrototherian
@Vijay Dev & fortran: No, he meant replace(). In Java 1.5+, there is an overloaded version of replace() that takes two CharSequences (which include Strings): download.oracle.com/javase/1.5.0/docs/api/java/lang/…Muchness
@mzuba let's say n=3: it first formats a string to look something like %03d (%% is to escape the percentage sign), which is the formatting code to add 3 padding zeroes, then formats 0 with that, leading to 000, and finally replaces each 0 with the stringsPrototherian
You can make the solution less ugly and easier to understand: String.format("%0"+n+"d", 0).replace("0", s)Garboard
C
88

If you're like me and want to use Google Guava and not Apache Commons. You can use the repeat method in the Guava Strings class.

Strings.repeat("-", 60);
Cardie answered 20/5, 2012 at 23:33 Comment(2)
... and get 3Mb of new dependencies.Andresandresen
@Andresandresen I thought it would go without saying, but don't include guava just to do a string repeat. My answer was about if you're already using guava anyway then this is how you'd do it.Cardie
H
55

With , you can also use Stream.generate.

import static java.util.stream.Collectors.joining;
...
String repeated = Stream.generate(() -> "abc").limit(3).collect(joining()); //"abcabcabc"

and you can wrap it in a simple utility method if needed:

public static String repeat(String str, int times) {
   return Stream.generate(() -> str).limit(times).collect(joining());
}
Hylan answered 29/12, 2014 at 14:16 Comment(1)
... or return IntStream.range(0, times).mapToObj(i -> str).collect(joining()); which parallelizes betterHylan
P
33

So you want to avoid loops?

Here you have it:

public static String repeat(String s, int times) {
    if (times <= 0) return "";
    else return s + repeat(s, times-1);
}

(of course I know this is ugly and inefficient, but it doesn't have loops :-p)

You want it simpler and prettier? use jython:

s * 3

Edit: let's optimize it a little bit :-D

public static String repeat(String s, int times) {
   if (times <= 0) return "";
   else if (times % 2 == 0) return repeat(s+s, times/2);
   else return s + repeat(s+s, times/2);
}

Edit2: I've done a quick and dirty benchmark for the 4 main alternatives, but I don't have time to run it several times to get the means and plot the times for several inputs... So here's the code if anybody wants to try it:

public class Repeat {
    public static void main(String[] args)  {
        int n = Integer.parseInt(args[0]);
        String s = args[1];
        int l = s.length();
        long start, end;

        start = System.currentTimeMillis();
        for (int i = 0; i < n; i++) {
            if(repeatLog2(s,i).length()!=i*l) throw new RuntimeException();
        }
        end = System.currentTimeMillis();
        System.out.println("RecLog2Concat: " + (end-start) + "ms");

        start = System.currentTimeMillis();
        for (int i = 0; i < n; i++) {
            if(repeatR(s,i).length()!=i*l) throw new RuntimeException();
        }               
        end = System.currentTimeMillis();
        System.out.println("RecLinConcat: " + (end-start) + "ms");

        start = System.currentTimeMillis();
        for (int i = 0; i < n; i++) {
            if(repeatIc(s,i).length()!=i*l) throw new RuntimeException();
        }
        end = System.currentTimeMillis();
        System.out.println("IterConcat: " + (end-start) + "ms");

        start = System.currentTimeMillis();
        for (int i = 0; i < n; i++) {
            if(repeatSb(s,i).length()!=i*l) throw new RuntimeException();
        }
        end = System.currentTimeMillis();
        System.out.println("IterStrB: " + (end-start) + "ms");
    }

    public static String repeatLog2(String s, int times) {
        if (times <= 0) {
            return "";
        }
        else if (times % 2 == 0) {
            return repeatLog2(s+s, times/2);
        }
        else {
           return s + repeatLog2(s+s, times/2);
        }
    }

    public static String repeatR(String s, int times) {
        if (times <= 0) {
            return "";
        }
        else {
            return s + repeatR(s, times-1);
        }
    }

    public static String repeatIc(String s, int times) {
        String tmp = "";
        for (int i = 0; i < times; i++) {
            tmp += s;
        }
        return tmp;
    }

    public static String repeatSb(String s, int n) {
        final StringBuilder sb = new StringBuilder();
        for(int i = 0; i < n; i++) {
            sb.append(s);
        }
        return sb.toString();
    }
}

It takes 2 arguments, the first is the number of iterations (each function run with repeat times arg from 1..n) and the second is the string to repeat.

So far, a quick inspection of the times running with different inputs leaves the ranking something like this (better to worse):

  1. Iterative StringBuilder append (1x).
  2. Recursive concatenation log2 invocations (~3x).
  3. Recursive concatenation linear invocations (~30x).
  4. Iterative concatenation linear (~45x).

I wouldn't ever guessed that the recursive function was faster than the for loop :-o

Have fun(ctional xD).

Prototherian answered 6/8, 2009 at 0:7 Comment(7)
+1 for recursion and obviously being a lisp hacker. I don't think this is so inefficient either, string concatenation isn't the warcrime it once was, because + really is just a stringBuilder UTH. See https://mcmap.net/q/41931/-string-concatenation-concat-vs-quot-quot-operator and schneide.wordpress.com/2009/02/23/… . I wonder how much all those stack pushes and pops from the recursion cost, or if hotspot takes care of them. Really wish I had the free time to benchmark it. Someone else maybe?Lafrance
@e5: fortran is right; this solution could be made more efficient. This implementation will unnecessarily create a new StringBuilder (and a new String) for each recursion. Still a nice solution though.Lavalava
@e5 I'd wish I were a Lisp hacker xD... If I were, I would have used a tail recursive function :-pPrototherian
Microbenchmarks don't work well in Java. Trying to measure the speed of your implementations like that is not good.Transfinite
@tecnotron I know, but still they are better than nothing... And the only 'surprise' was the slight difference between the naive loop concatenation and linear recursion.Prototherian
The recursion is a loop.Vimineous
The loop is a recursion.Prototherian
F
21

This contains less characters than your question

public static String repeat(String s, int n) {
    if(s == null) {
        return null;
    }
    final StringBuilder sb = new StringBuilder(s.length() * n);
    for(int i = 0; i < n; i++) {
        sb.append(s);
    }
    return sb.toString();
}
Frampton answered 5/8, 2009 at 19:23 Comment(8)
It contains more characters than my answer StringUtils.repeat(str, n).Lafrance
Unless you're already using Apache Commons, this answer is a lot less hassle - no downloading another library, including it in your classpath, making sure its license is compatible with yours, etc.Surfboarding
Please, never return null - in that case return an empty string, allowing you to always use the returned value unchecked. Otherwise, what I would recommend the poster to use.Volscian
Well, there are three ways to handle if s is null. 1. Pass the error (return null), 2. Hide the error (return ""), 3. Throw an NPE. Hiding the error and throwing an NPE are not cool, so I passed the error.Frampton
@EthanHeilman add the 2MB worth of commons-lang3.3.1-sources and you're not that good anymore ;) But if someone already has commons-lang, I support your answer.Etruria
@Frampton "passing the error" as you call it is not a good thing to do. It makes it harder to figure out where the error originally came from. You could reasonably do what TWiStErRob said and treat null as "null" (as the StringBuilder already does). Otherwise, the right thing to do is throw an NPE. If the caller passes garbage input, for which there is no sensible output, it's right that they should get garbage thrown back at them.Nay
Is it repeat's task to forbid the use of null and crash your program if you do? Returning null when given a null is the most neutral way to handle this particular input.Assistant
This code snippet contains even less characters while still using StringBuilder :DI
R
9

based on fortran's answer, this is a recusive version that uses a StringBuilder:

public static void repeat(StringBuilder stringBuilder, String s, int times) {
    if (times > 0) {
        repeat(stringBuilder.append(s), s, times - 1);
    }
}

public static String repeat(String s, int times) {
    StringBuilder stringBuilder = new StringBuilder(s.length() * times);
    repeat(stringBuilder, s, times);
    return stringBuilder.toString();
}
Rajput answered 6/8, 2009 at 3:57 Comment(1)
looping rather than recursion would reduce the # of stack frames for large numbers of repeats.Dvorak
R
7

using Dollar is simple as typing:

@Test
public void repeatString() {
    String string = "abc";
    assertThat($(string).repeat(3).toString(), is("abcabcabc"));
}

PS: repeat works also for array, List, Set, etc

Rajput answered 1/2, 2010 at 16:1 Comment(2)
is the assertThat() method really needed?Transfinite
Link in answer gives "404 | Repository not found".Isolda
B
7

I wanted a function to create a comma-delimited list of question marks for JDBC purposes, and found this post. So, I decided to take two variants and see which one performed better. After 1 million iterations, the garden-variety StringBuilder took 2 seconds (fun1), and the cryptic supposedly more optimal version (fun2) took 30 seconds. What's the point of being cryptic again?

private static String fun1(int size) {
    StringBuilder sb = new StringBuilder(size * 2);
    for (int i = 0; i < size; i++) {
        sb.append(",?");
    }
    return sb.substring(1);
}

private static String fun2(int size) {
    return new String(new char[size]).replaceAll("\0", ",?").substring(1);
}
Bulldog answered 6/12, 2012 at 14:42 Comment(1)
I makes sense that the second one would take much longer. It is performing a string search and then modifying the string character by character.Lafrance
L
7

OOP Solution

Nearly every answer proposes a static function as a solution, but thinking Object-Oriented (for reusability-purposes and clarity) I came up with a Solution via Delegation through the CharSequence-Interface (which also opens up usability on mutable CharSequence-Classes).

The following Class can be used either with or without Separator-String/CharSequence and each call to "toString()" builds the final repeated String. The Input/Separator are not only limited to String-Class, but can be every Class which implements CharSequence (e.g. StringBuilder, StringBuffer, etc)!

Source-Code:

/**
 * Helper-Class for Repeating Strings and other CharSequence-Implementations
 * @author Maciej Schuttkowski
 */
public class RepeatingCharSequence implements CharSequence {
    final int count;
    CharSequence internalCharSeq = "";
    CharSequence separator = "";
    /**
     * CONSTRUCTOR - RepeatingCharSequence
     * @param input CharSequence to repeat
     * @param count Repeat-Count
     */
    public RepeatingCharSequence(CharSequence input, int count) {
        if(count < 0)
            throw new IllegalArgumentException("Can not repeat String \""+input+"\" less than 0 times! count="+count);
        if(count > 0)
            internalCharSeq = input;
        this.count = count;
    }
    /**
     * CONSTRUCTOR - Strings.RepeatingCharSequence
     * @param input CharSequence to repeat
     * @param count Repeat-Count
     * @param separator Separator-Sequence to use
     */
    public RepeatingCharSequence(CharSequence input, int count, CharSequence separator) {
        this(input, count);
        this.separator = separator;
    }

    @Override
    public CharSequence subSequence(int start, int end) {
        checkBounds(start);
        checkBounds(end);
        int subLen = end - start;
        if (subLen < 0) {
            throw new IndexOutOfBoundsException("Illegal subSequence-Length: "+subLen);
        }
        return (start == 0 && end == length()) ? this
                    : toString().substring(start, subLen);
    }
    @Override
    public int length() {
        //We return the total length of our CharSequences with the separator 1 time less than amount of repeats:
        return count < 1 ? 0
                : ( (internalCharSeq.length()*count) + (separator.length()*(count-1)));
    }
    @Override
    public char charAt(int index) {
        final int internalIndex = internalIndex(index);
        //Delegate to Separator-CharSequence or Input-CharSequence depending on internal index:
        if(internalIndex > internalCharSeq.length()-1) {
            return separator.charAt(internalIndex-internalCharSeq.length());
        }
        return internalCharSeq.charAt(internalIndex);
    }
    @Override
    public String toString() {
        return count < 1 ? ""
                : new StringBuilder(this).toString();
    }

    private void checkBounds(int index) {
        if(index < 0 || index >= length())
            throw new IndexOutOfBoundsException("Index out of Bounds: "+index);
    }
    private int internalIndex(int index) {
        // We need to add 1 Separator-Length to total length before dividing,
        // as we subtracted one Separator-Length in "length()"
        return index % ((length()+separator.length())/count);
    }
}

Usage-Example:

public static void main(String[] args) {
    //String input = "12345";
    //StringBuffer input = new StringBuffer("12345");
    StringBuilder input = new StringBuilder("123");
    //String separator = "<=>";
    StringBuilder separator = new StringBuilder("<=");//.append('>');
    int repeatCount = 2;

    CharSequence repSeq = new RepeatingCharSequence(input, repeatCount, separator);
    String repStr = repSeq.toString();

    System.out.println("Repeat="+repeatCount+"\tSeparator="+separator+"\tInput="+input+"\tLength="+input.length());
    System.out.println("CharSeq:\tLength="+repSeq.length()+"\tVal="+repSeq);
    System.out.println("String :\tLength="+repStr.length()+"\tVal="+repStr);

    //Here comes the Magic with a StringBuilder as Input, as you can append to the String-Builder
    //and at the same Time your Repeating-Sequence's toString()-Method returns the updated String :)
    input.append("ff");
    System.out.println(repSeq);
    //Same can be done with the Separator:
    separator.append("===").append('>');
    System.out.println(repSeq);
}

Example-Output:

Repeat=2    Separator=<=    Input=123   Length=3
CharSeq:    Length=8    Val=123<=123
String :    Length=8    Val=123<=123
123ff<=123ff
123ff<====>123ff
Latrice answered 6/8, 2015 at 16:48 Comment(0)
R
6

using only JRE classes (System.arraycopy) and trying to minimize the number of temp objects you can write something like:

public static String repeat(String toRepeat, int times) {
    if (toRepeat == null) {
        toRepeat = "";
    }

    if (times < 0) {
        times = 0;
    }

    final int length = toRepeat.length();
    final int total = length * times;
    final char[] src = toRepeat.toCharArray();
    char[] dst = new char[total];

    for (int i = 0; i < total; i += length) {
        System.arraycopy(src, 0, dst, i, length);
    }

    return String.copyValueOf(dst);
}

EDIT

and without loops you can try with:

public static String repeat2(String toRepeat, int times) {
    if (toRepeat == null) {
        toRepeat = "";
    }

    if (times < 0) {
        times = 0;
    }

    String[] copies = new String[times];
    Arrays.fill(copies, toRepeat);
    return Arrays.toString(copies).
              replace("[", "").
              replace("]", "").
              replaceAll(", ", "");
}

EDIT 2

using Collections is even shorter:

public static String repeat3(String toRepeat, int times) {
    return Collections.nCopies(times, toRepeat).
           toString().
           replace("[", "").
           replace("]", "").
           replaceAll(", ", "");
}

however I still like the first version.

Rajput answered 5/8, 2009 at 19:53 Comment(8)
-1: too clever by half. If your aim is to make you code readable or efficient, these "solutions" are not a good idea. 'repeat' could simply be rewritten using a StringBuilder (setting the initial capacity). And 'repeat2' / 'repeat3' are really inefficient, and depend on the unspecified syntax of the String produced by String[].toString().Zia
@Thorb: absolutely, with this code you cannot use "metacharacter", [],Rajput
@Stephen: the question was edited to request explicitly no loops. A StringBuilder based answer was already provided so I avoided to post a duplicateRajput
@Stephan: I cannot figure out the downvote. My edited answer is loop-free as requeted. There are no requests about efficiency. I think that this question is just an intellectual effort to produce a concatenation without a loop.Rajput
@Stephan: String produced via Collection.toString (and Arrays.toString) are clearly specified in AbstractCollection.toString: " The string representation consists of a list of the collection's elements in the order they are returned by its iterator, enclosed in square brackets ("[]"). Adjacent elements are separated by the characters ", " (comma and space)."Rajput
@dfa: I take back my point about toString() being unspecified. (I didn't know that ...). But I don't read the OP as saying that this is merely an intellectual effort. Rather I think he is serious ... and seriously misguided ... and might even copy-and-paste one of your "too clever" solutions into his code!Zia
IF you're only interested in repeating a single char, then Arrays.fill would be lovely. i.e. char[] data = new char[count]; Arrays.fill(data, toRepeat); return new String(data);Pimbley
Your versions using replace are catastrophically broken, because they remove all bracket characters and comma-space sequences in the inputs. Your basic loop version is alright, although the input value coercion is a bit dodgy, and you could avoid calling toCharArray() by using String.getChars.Nay
L
6

Not the shortest, but (i think) the fastest way is to use the StringBuilder:

 /**
   * Repeat a String as many times you need.
   *
   * @param i - Number of Repeating the String.
   * @param s - The String wich you want repeated.
   * @return The string n - times.
   */
  public static String repeate(int i, String s) {
    StringBuilder sb = new StringBuilder();
    for (int j = 0; j < i; j++)
      sb.append(s);
    return sb.toString();
  }
Lipo answered 12/10, 2017 at 12:58 Comment(0)
B
5

If speed is your concern, then you should use as less memory copying as possible. Thus it is required to work with arrays of chars.

public static String repeatString(String what, int howmany) {
    char[] pattern = what.toCharArray();
    char[] res = new char[howmany * pattern.length];
    int length = pattern.length;
    for (int i = 0; i < howmany; i++)
        System.arraycopy(pattern, 0, res, i * length, length);
    return new String(res);
}

To test speed, a similar optimal method using StirngBuilder is like this:

public static String repeatStringSB(String what, int howmany) {
    StringBuilder out = new StringBuilder(what.length() * howmany);
    for (int i = 0; i < howmany; i++)
        out.append(what);
    return out.toString();
}

and the code to test it:

public static void main(String... args) {
    String res;
    long time;

    for (int j = 0; j < 1000; j++) {
        res = repeatString("123", 100000);
        res = repeatStringSB("123", 100000);
    }

    time = System.nanoTime();
    res = repeatString("123", 1000000);
    time = System.nanoTime() - time;
    System.out.println("elapsed repeatString: " + time);

    time = System.nanoTime();
    res = repeatStringSB("123", 1000000);
    time = System.nanoTime() - time;
    System.out.println("elapsed repeatStringSB: " + time);

}

And here the run results from my system:

elapsed repeatString: 6006571
elapsed repeatStringSB: 9064937

Note that the test for loop is to kick in JIT and have optimal results.

Breechloader answered 18/5, 2017 at 23:28 Comment(0)
C
5

a straightforward one-line solution:
requires Java 8

Collections.nCopies( 3, "abc" ).stream().collect( Collectors.joining() );
Chiquia answered 24/10, 2019 at 17:50 Comment(0)
V
4

for the sake of readability and portability:

public String repeat(String str, int count){
    if(count <= 0) {return "";}
    return new String(new char[count]).replace("\0", str);
}
Victim answered 17/4, 2016 at 21:5 Comment(0)
H
3

If you are worried about performance, just use a StringBuilder inside the loop and do a .toString() on exit of the Loop. Heck, write your own Util Class and reuse it. 5 Lines of code max.

Hardandfast answered 5/8, 2009 at 19:21 Comment(0)
E
2

I really enjoy this question. There is a lot of knowledge and styles. So I can't leave it without show my rock and roll ;)

{
    String string = repeat("1234567890", 4);
    System.out.println(string);
    System.out.println("=======");
    repeatWithoutCopySample(string, 100000);
    System.out.println(string);// This take time, try it without printing
    System.out.println(string.length());
}

/**
 * The core of the task.
 */
@SuppressWarnings("AssignmentToMethodParameter")
public static char[] repeat(char[] sample, int times) {
    char[] r = new char[sample.length * times];
    while (--times > -1) {
        System.arraycopy(sample, 0, r, times * sample.length, sample.length);
    }
    return r;
}

/**
 * Java classic style.
 */
public static String repeat(String sample, int times) {
    return new String(repeat(sample.toCharArray(), times));
}

/**
 * Java extreme memory style.
 */
@SuppressWarnings("UseSpecificCatch")
public static void repeatWithoutCopySample(String sample, int times) {
    try {
        Field valueStringField = String.class.getDeclaredField("value");
        valueStringField.setAccessible(true);
        valueStringField.set(sample, repeat((char[]) valueStringField.get(sample), times));
    } catch (Exception ex) {
        throw new RuntimeException(ex);
    }
}

Do you like it?

Enidenigma answered 2/4, 2013 at 21:20 Comment(1)
In my more extreme test, I produce a 1,700,000,000 (1.7 gigas) string repeat length,, using -Xms4937mKirtle
F
2
public static String repeat(String str, int times) {
    int length = str.length();
    int size = length * times;
    char[] c = new char[size];
    for (int i = 0; i < size; i++) {
        c[i] = str.charAt(i % length);
    }
    return new String(c);
}
Feeble answered 31/5, 2013 at 12:37 Comment(0)
S
2

Simple loop

public static String repeat(String string, int times) {
    StringBuilder out = new StringBuilder();
    while (times-- > 0) {
        out.append(string);
    }
    return out.toString();
}
Sowens answered 25/6, 2013 at 11:49 Comment(1)
pass times to StringBuilder constructor.Webbing
B
2

Try this out:

public static char[] myABCs = {'a', 'b', 'c'};
public static int numInput;
static Scanner in = new Scanner(System.in);

public static void main(String[] args) {
    System.out.print("Enter Number of Times to repeat: ");
    numInput = in.nextInt();
    repeatArray(numInput);
}

public static int repeatArray(int y) {
    for (int a = 0; a < y; a++) {
        for (int b = 0; b < myABCs.length; b++) {
            System.out.print(myABCs[b]);                
        }
        System.out.print(" ");
    }
    return y;
}
Brunette answered 13/11, 2013 at 14:25 Comment(0)
A
2

Using recursion, you can do the following (using ternary operators, one line max):

public static final String repeat(String string, long number) {
    return number == 1 ? string : (number % 2 == 0 ? repeat(string + string, number / 2) : string + repeat(string + string, (number - 1) / 2));
}

I know, it's ugly and probably not efficient, but it's one line!

Annulet answered 8/6, 2015 at 0:31 Comment(3)
This is the approach I would take but why do more checks than is needed? return number > 0 ? string + repeat(string, number-1) : "";Cacophony
Oh, seems niczm25 answered with it belowCacophony
@Cacophony main reason so that this way is O(log N) average rather than O(N) always. Slightly more optimization than the other one, though still bad nevertheless.Annulet
L
2

If you only know the length of the output string (and it may be not divisible by the length of the input string), then use this method:

static String repeat(String s, int length) {
    return s.length() >= length ? s.substring(0, length) : repeat(s + s, length);
}

Usage demo:

for (int i = 0; i < 50; i++)
    System.out.println(repeat("_/‾\\", i));

Don't use with empty s and length > 0, since it's impossible to get the desired result in this case.

Letti answered 18/5, 2020 at 19:16 Comment(0)
I
2

Seeing a number of StringBuilder related answers, I believe it's also worth mentioning that there are new StringBuilder.repeat and StringBuffer.repeat methods added in Java 21 to simplify the appending of multiple copies of characters or strings:

System.out.println(new StringBuilder().repeat('A', 10)); // AAAAAAAAAA

System.out.println(new StringBuilder().repeat("A1", 2)); // A1A1
I answered 7/9, 2023 at 21:15 Comment(0)
N
1

Despite your desire not to use loops, I think you should use a loop.

String repeatString(String s, int repetitions)
{
    if(repetitions < 0) throw SomeException();

    else if(s == null) return null;

    StringBuilder stringBuilder = new StringBuilder(s.length() * repetitions);

    for(int i = 0; i < repetitions; i++)
        stringBuilder.append(s);

    return stringBuilder.toString();
}

Your reasons for not using a for loop are not good ones. In response to your criticisms:

  1. Whatever solution you use will almost certainly be longer than this. Using a pre-built function only tucks it under more covers.
  2. Someone reading your code will have to figure out what you're doing in that non-for-loop. Given that a for-loop is the idiomatic way to do this, it would be much easier to figure out if you did it with a for loop.
  3. Yes someone might add something clever, but by avoiding a for loop you are doing something clever. That's like shooting yourself in the foot intentionally to avoid shooting yourself in the foot by accident.
  4. Off-by-one errors are also mind-numbingly easy to catch with a single test. Given that you should be testing your code, an off-by-one error should be easy to fix and catch. And it's worth noting: the code above does not contain an off-by-one error. For loops are equally easy to get right.
  5. So don't reuse variables. That's not the for-loop's fault.
  6. Again, so does whatever solution you use. And as I noted before; a bug hunter will probably be expecting you to do this with a for loop, so they'll have an easier time finding it if you use a for loop.
Nicely answered 5/8, 2009 at 21:31 Comment(9)
-1. Here's two exercises for you: a) run your code with repetitions = -5. b) download Commons Lang and run repeatString('a', 1000) a million times in a loop; do the same with your code; compare the times. For extra credit do the same with repeatString('ab', 1000).Litigable
Fixed the first issue. As for the second issue, right, because speed is the ONLY concern. Given that the OP considers for loops to be the bane of programming, he's more concerned about readability than micro-optimizations.Nicely
Are you arguing that your code is more readable then StringUtils.repeat("ab",1000)? Because that was my answer that you've downvoted. It also performs better and has no bugs.Litigable
So you're coming out and admitting that you downvoted my answer because I downvoted yours, not on the merits of my answer? For your information, I downvoted your answer, not because of readability, but because as dfa said, "using a one-method-dependency for the simplicity's sake in the long run can resulting in a jar-hell" in addition to my own criticism, "What makes you think that this doesn't simply tuck the for loop away in another function?". Since the first is a concern and the second is obviously a concern to the OP, I thought my downvote was justified.Nicely
"Admitting"? I explicitly said "-1" and specified the reasons why. "Jar hell" is a non-issue; it's been addressed in comments above. OP was not trying to avoid loops at all costs; he did not want to write one if there was already a library function that would do this task for him. Your code (which uses the loop; is not as readable; had a bug; and doesn't perform well) is a perfect illustration why.Litigable
"Jar hell" may be a non-issue with Maven, but one shouldn't have to install an entire dependency system and a library just to implement a few lines of code. If he plans to use it elsewhere, fine, but I saw no indication of that in the original post. As for avoiding loops at all costs: the OP said, "I try to avoid for loops at all costs because:" and listed a bunch of reasons. So I think that he WAS trying to avoid loops at all costs.Nicely
Read the 2nd sentence in the question you're quoting. "I try to avoid for loops at all costs because" was added to the question as a clarification in response to Andrew Hare's answer after my reply - not that it matters because if the position you're taking is "answer is bad if loop is used anywhere" there are no answers to the OP question. Even dfa's solutions - inventive as they are - use for loops inside. "jar hell" was replied to above; commons lang is used in every decent-sized application anyway and thus doesn't add a new dependency.Litigable
@Litigable at this point I'm pretty sure imagist is trolling. I really have a hard time seeing how anyone could read what I wrote and seriously think the responses typed above.Lafrance
@Litigable my answers don't have any loops at all :-pPrototherian
O
0

here is the latest Stringutils.java StringUtils.java

    public static String repeat(String str, int repeat) {
    // Performance tuned for 2.0 (JDK1.4)

    if (str == null) {
        return null;
    }
    if (repeat <= 0) {
        return EMPTY;
    }
    int inputLength = str.length();
    if (repeat == 1 || inputLength == 0) {
        return str;
    }
    if (inputLength == 1 && repeat <= PAD_LIMIT) {
        return repeat(str.charAt(0), repeat);
    }

    int outputLength = inputLength * repeat;
    switch (inputLength) {
        case 1 :
            return repeat(str.charAt(0), repeat);
        case 2 :
            char ch0 = str.charAt(0);
            char ch1 = str.charAt(1);
            char[] output2 = new char[outputLength];
            for (int i = repeat * 2 - 2; i >= 0; i--, i--) {
                output2[i] = ch0;
                output2[i + 1] = ch1;
            }
            return new String(output2);
        default :
            StringBuilder buf = new StringBuilder(outputLength);
            for (int i = 0; i < repeat; i++) {
                buf.append(str);
            }
            return buf.toString();
    }
    }

it doesn't even need to be this big, can be made into this, and can be copied and pasted into a utility class in your project.

    public static String repeat(String str, int num) {
    int len = num * str.length();
    StringBuilder sb = new StringBuilder(len);
    for (int i = 0; i < times; i++) {
        sb.append(str);
    }
    return sb.toString();
    }

So e5, I think the best way to do this would be to simply use the above mentioned code,or any of the answers here. but commons lang is just too big if it's a small project

Ora answered 10/8, 2011 at 23:55 Comment(1)
I don't think there is much else you can do... excet maybe an AOT!!Ora
B
0

I created a recursive method that do the same thing you want.. feel free to use this...

public String repeat(String str, int count) {
    return count > 0 ?  repeat(str, count -1) + str: "";
}

i have the same answer on Can I multiply strings in java to repeat sequences?

Beata answered 7/1, 2016 at 9:15 Comment(2)
Needless string reallocation, and recursion overhead... bad, bad, not good.Angelenaangeleno
This will be slow. Not recommended! Use StringBuilder instead.Latinism
P
0

Consolidated for quick reference:

public class StringRepeat {

// Java 11 has built-in method - str.repeat(3);
// Apache - StringUtils.repeat(3);
// Google - Strings.repeat("",n);
// System.arraycopy

static String repeat_StringBuilderAppend(String str, int n) {

    if (str == null || str.isEmpty())
        return str;

    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < n; i++) {
        sb.append(str);
    }
    return sb.toString();
}

static String repeat_ArraysFill(String str, int n) {
    String[] strs = new String[n];
    Arrays.fill(strs, str);
    return Arrays.toString(strs).replaceAll("\\[|\\]|,| ", "");
}

static String repeat_Recursion(String str, int n) {
    if (n <= 0)
        return "";
    else
        return str + repeat_Recursion(str, n - 1);
}

static String repeat_format1(String str, int n) {
    return String.format(String.format("%%%ds", n), " ").replace(" ", str);
}

static String repeat_format2(String str, int n) {
    return new String(new char[n]).replace("\0", str);
}

static String repeat_format3(String str, int n) {
    return String.format("%0" + n + "d", 0).replace("0", str);
}

static String repeat_join(String str, int n) {
    return String.join("", Collections.nCopies(n, str));
}

static String repeat_stream(String str, int n) {
    return Stream.generate(() -> str).limit(n).collect(Collectors.joining());
}

public static void main(String[] args) {
    System.out.println(repeat_StringBuilderAppend("Mani", 3));
    System.out.println(repeat_ArraysFill("Mani", 3));
    System.out.println(repeat_Recursion("Mani", 3));
    System.out.println(repeat_format1("Mani", 3));
    System.out.println(repeat_format2("Mani", 3));
    System.out.println(repeat_format3("Mani", 3));
    System.out.println(repeat_join("Mani", 3));
    System.out.println(repeat_stream("Mani", 3));

}

}

Prebendary answered 18/4, 2020 at 11:39 Comment(0)
K
-1
public static String rep(int a,String k)

       {
           if(a<=0)
                return "";
           else 
           {a--;
               return k+rep(a,k);
       }

You can use this recursive method for you desired goal.

Kenyakenyatta answered 9/8, 2019 at 16:3 Comment(0)
W
-3
repeated = str + str + str;

Sometimes simple is best. Everyone reading the code can see what's happening.

And the compiler will do the fancy stuff with StringBuilder behind the scenes for you.

Waikiki answered 9/10, 2014 at 13:23 Comment(2)
Thats stupid for many repeats. I think nobody wants write "str +" hundred times. And the question asks for a function/method to repeat string automatically.Whiz
That only works when n is an author-time constant.Sapajou

© 2022 - 2024 — McMap. All rights reserved.