Javaで文字列を繰り返す簡単な方法


598

Stringをn回繰り返すことができる単純なcommonsメソッドまたは演算子を探しています。forループを使用してこれを記述できることはわかっていますが、必要な場合はいつでもforループを避け、単純な直接メソッドがどこかに存在する必要があります。

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

repeated.equals("abcabcabc");

関連:

文字列を繰り返すjavascript 指定した回数別の文字列を繰り返すことによってNSStringを作成する

編集済み

forループが完全に必要でない場合は、次の理由で回避しようとします。

  1. 別の関数に隠れている場合でも、コードの行数が増えます。

  2. 私のコードを読んでいる人は、そのforループで私が何をしているのかを理解する必要があります。コメントされていて、意味のある変数名がある場合でも、「賢い」ことを行わないようにする必要があります。

  3. プログラマーはforループに巧妙なものを入れるのが大好きです。たとえ「意図したことだけを行う」と書いても、誰かがやって来て巧妙な「修正」を追加することを妨げるものではありません。

  4. 彼らはしばしば間違いを犯しやすい。インデックスを含むforループは、1つのバグによって生成される傾向があります。

  5. forループはしばしば同じ変数を再利用するため、スコープバグを見つけるのが非常に困難になる可能性が高くなります。

  6. forループは、バグハンターが見なければならない場所の数を増やします。


35
forループがいくつかの実際の問題を引き起こす可能性があることを理解しています。しかし、可読性、保守性、速度が犠牲になると逆効果になるため、forループを「絶対に」回避しないでください。これはそれらのケースの1つです。
イマジスト

9
「コードが別の関数に隠れていても、コードの行数が増える」...わあ、すごい。LoCではなくBig-O
パイロリスティカル2009

7
@imagist私は可読性と保守性を犠牲にする状況でforループを避けています。ここでは速度を最も重要でない問題と見なしています(実際には問題ではありません)。forループは使いすぎだと思います。デフォルトのソリューションではなく、必要な場合にのみforループを使用する方法を学んでいます。
Ethan Heilman、

3
@Pyrolisticalパフォーマンスや漸近的な利点を主張していません。むしろ、より少ないコードを記述し、ホイールを再発明するのではなくライブラリー関数を使用することで、可読性を高めながらバグの表面積(コード行)を減らします。どちらも良いことだと思います。
イーサンハイルマン、

4
@ e5;数年後に投稿して申し訳ありません。この質問はとても適切だと思います。メソッドに挿入する場合、引数をテストする必要があります(回> = 0)、スローされるエラーなど。これにより、堅牢性だけでなく、読み取るコード行も追加されます。文字列の繰り返しは明白です。コメント行やjavadocがなくても、コードを読んだ人はstring.repeatの動作を正確に知っています。安定したライブラリを使用している場合、非常に単純な関数にはバグがないと考えるのが妥当です。 YETは、私たちが心配する必要があるなんらかの形の「堅牢性」チェックを導入しています。10個の改善を依頼できれば、これは(一種の)ものです。
AgostinoX 2011

回答:


230

String::repeat

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

Java 11の新機能は、String::repeat要求されたとおりの処理を実行するメソッドです。

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

そのJavadocは言う:

/**
 * 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
 */ 


7
私もjavaの見ていない9路上で、まだを(としませんのために長いと-時間...)11は ...どうやら船に設定されている
javadba

1
おそらく明白な、しかし、あなたはあまりにも文字列リテラルでこのメソッドを呼び出すことができます"abc".repeat(3)
Boann

895

これが最短バージョンです(Java 1.5以降が必要です):

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

どこにnあなたが文字列を繰り返したい回数であるとs繰り返しに文字列です。

インポートやライブラリは必要ありません。


22
全然難読化されていないと思います。プリミティブ型(char[]この場合は)はnullでインスタンス化され、次にStringからが作成されchar[]、nullは目的replaced()の文字で作成されますs
Amarok

32
これは非常に賢い(+1)ですが、forループがコードをより明確にすることがよくあることをかなり証明していると思います
Richard Tingle

75
難読化について不平を言う人にとって、読みやすさは読み書き能力に依存します。これは、それが何をするのか、すぐにそれを見ることができない人のための教育において完全に明確です。ところで、これはJavaで得られるものです。
dansalmo 2014年

11
パフォーマンス...replace('\0', str)を向上させるには、文字列バージョンの代わりに使用する必要があります。
user686249 2014年

11
@ user686249:しか存在しないのでreplace(char oldChar, char newChar)replace(CharSequence target, CharSequence replacement)それがどのように機能するかわかりません
user102008

334

Java <= 7を使用している場合、これは「簡潔」です。

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

Java 8と上より読みやすい方法があります:

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

最後に、Java 11以降では、repeat​(int count)これに固有の新しいメソッドがあります(link

"abc".repeat(12);

または、プロジェクトでJavaライブラリを使用している場合は、さらに多くのオプションがあります。

以下のためのApache Commonsの

StringUtils.repeat("abc", 12);

以下のためのGoogleのグァバ

Strings.repeat("abc", 12);

4
前者は、nゼロの場合に例外を発生させます。
saka1029

java 8の例はコンパイルされません->タイプの不一致:List <Character>からCharSequenceに変換できません
Arigion

6
@Arigion sは文字列ではなく、文字列である必要がありますChar
Caner

@Canerありがとう。すみません、お詫び申し上げます。どうやら昨日は疲れすぎたらしい。反対投票について申し訳ありません。私はできる限り早く反対票を削除します(質問が編集されるまでブロックされます)
Arigion '10

@Arigionは問題ありません、sが文字列であることを明らかにしました
Caner

312

Commons Lang StringUtils.repeat()

使用法:

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

repeated.equals("abcabcabc");

99
単純化のために1メソッド依存を長期的に使用すると、jar-hellになる可能性があります
dfa

81
承知しました。ただし、commons langを除きます。Commons langがない5000 LOCSを超えるプロジェクトを見たことがありません。
イーサンハイルマン、

11
Commons Langはオープンソースです-ダウンロードしてご覧ください。もちろん、内部にループがありますが、それほど単純ではありません。その実装のプロファイリングと最適化には多くの努力が費やされました。
ChssPly76 2009

28
パフォーマンス上の理由でループを回避していません(質問の私の理由をお読みください)。誰かがStringUtils.repeatを見たとき、彼らは私が何をしているかを知っています。彼らは私がリピートの自分のバージョンを書こうとし、ミスをしたことを心配する必要はありません。原子認知単位です!
イーサンハイルマン、

7
@ThorbjørnRavn Andersen-状況が
悪化

140

Java 8 String.joinは、これと組み合わせてこれを行うきちんとした方法を提供しますCollections.nCopies

// say hello 100 times
System.out.println(String.join("", Collections.nCopies(100, "hello")));

7
ありがとうございました!Androidの場合、String.join()の代わりにTextUtils.join()を使用できます
MinaHany

2
この回答をありがとうございます。これは、外部APIオーダーユーティリティメソッドを使用しない最もクリーンな方法のようです。とても良い!!
Andreas M. Oberheim 2017年

2
この方法の良い点は、結合を使用すると、CSVリストを作成する場合などに非常に便利な区切り文字を指定できることです。他のすべての方法では、別の操作で削除する必要のある終了結合文字があります。
DroidOS 2018年

102

標準の文字列関数のみを使用し、明示的なループを使用しない方法は次のとおりです。

// create a string made up of  n  copies of  s
repeated = String.format(String.format("%%%ds", n), " ").replace(" ",s);

5
すごい:-) nがゼロになることに注意してください…!
Yang Meyer

4
@Vijay Dev&fortran:いいえ、彼はを意味したreplace()。ジャワ1.5+では、オーバーロードのバージョンが存在するreplace()ことは、2つの取りCharSequenceS(これにはString:S)をdownload.oracle.com/javase/1.5.0/docs/api/java/lang/...
user102008

79
痛い。これは醜いです。
KarelBílek11年

8
@mzubaみましょうと言うn=3:それのような外観のものに最初の形式の文字列%03d%%3つのパディングゼロを追加するための書式設定コードであるパーセント記号をエスケープすることである)、そしてフォーマット0につながることで000、最終的にそれぞれ置き換え0た文字列とを
Fortran

15
ソリューションの見やすさを向上させ
Artur

87

あなたが私のようなもので、Apache CommonsではなくGoogle Guavaを使用したい場合。Guava Stringsクラスでrepeatメソッドを使用できます。

Strings.repeat("-", 60);

2
...そして3Mbの新しい依存関係を取得します。
MonoThreaded

6
@MonoThreaded言うまでもないだろうと思ったが、文字列の繰り返しを行うためだけにguavaを含めないでください。私の答えは、とにかくすでにグアバを使用しているなら、これがあなたがそれをする方法であるということでした。
ジャック

53

、あなたも使うことができますStream.generate

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

必要に応じて、シンプルなユーティリティメソッドでラップできます。

public static String repeat(String str, int times) {
   return Stream.generate(() -> str).limit(times).collect(joining());
}

6
...またはreturn IntStream.range(0, times).mapToObj(i -> str).collect(joining());、より適切に並列化
AlexisC。

32

だからあなたはループを避けたいですか?

ここにあります:

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

(もちろん、これは醜く非効率的ですが、ループがありません:-p)

よりシンプルできれいにしたいですか?jythonを使用します。

s * 3

編集:少し最適化しましょう:-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:私は4つの主要な代替案の迅速で汚いベンチマークを行いましたが、平均を取得して複数の入力の時間をプロットするために数回実行する時間はありません...だから誰かが望むならここにコードがありますそれを試す:

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

これは2つの引数を取ります。1つ目は反復の数(各関数は1..nからのargの繰り返しで実行されます)で、2つ目は繰り返す文字列です。

これまでのところ、さまざまな入力で実行されている時間をすばやく検査すると、ランキングは次のようになります(良い方から悪い方へ)。

  1. 反復的なStringBuilder追加(1x)。
  2. 再帰的連結log2呼び出し(〜3x)。
  3. 再帰的連結線形呼び出し(〜30x)。
  4. 反復連結線形(〜45x)。

再帰関数がforループよりも速いとは思いもしませんでした:-o

楽しんでください(ctional xD)。


1
再帰のために+1し、明らかにlispハッカーであること。+は実際には単なるstringBuilder UTHであるため、文字列の連結は以前のような犯罪ではありません。stackoverflow.com/questions/47605/java-string-concatenation およびschneide.wordpress.com/2009/02/23/…を参照してください 。これらのスタックが再帰コストからどれだけプッシュまたはポップするか、またはホットスポットがそれらを処理するかどうか、私は疑問に思います。私がそれをベンチマークするための自由な時間があったら本当に望みます。多分誰か?
イーサンハイルマン、

@ e5:Fortranは正しいです。このソリューションをより効率的にすることができます。この実装は、再帰ごとに不必要に新しいStringBuilder(および新しいString)を作成します。それでも素晴らしい解決策です。
ロブ・

3
@ e5私はLispハッカーxDになりたいと思います...もしそうなら、私はテール再帰関数を使用したでしょう:-p
fortran

1
マイクロベンチマークは、Javaではうまく機能しません。そのような実装の速度を測定しようとするのはよくありません。
ceklock

@tecnotron私は知っていますが、それでも何もないよりはましです...そして、唯一の「驚き」は、単純なループ連結と線形再帰のわずかな違いでした。
Fortran

20

これはあなたの質問より少ない文字を含んでいます

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

4
私の回答StringUtils.repeat(str、n)よりも多くの文字が含まれています。
イーサンハイルマン、

8
無必ずそのライセンス等あなた、と互換性のある作り、あなたのクラスパスに含め、別のライブラリをダウンロード-あなたはすでにApacheのコモンズを使用している場合を除き、この答えははるかに少ない手間である
ポールTomblin

7
nullを返さないでください。その場合は空の文字列が返されるため、返された値を常にチェックなしで使用できます。それ以外の場合は、ポスターの使用をお勧めします。
するThorbjörnRavnアンデルセン

7
sがnullの場合、3つの方法で処理できます。1.エラーを渡す(nullを返す)、2。エラーを非表示にする( ""を返す)、3。NPEをスローします。エラーを非表示にしてNPEをスローするのはクールではないので、エラーを渡しました。
Pyrolistical 2009

1
@EthanHeilmanは2MBの価値を追加し、commons-lang3.3.1-sourcesあなたはもうそれほど良くはありません;)しかし、誰かがすでに持っているならcommons-lang、私はあなたの答えをサポートします。
TWiStErRob 2013年

9

fortranの回答に基づくと、これは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();
}

1
再帰ではなくループすると、多数の繰り返しでスタックフレームの数が減ります。
La-comadreja 14年

7

ドルを使用すると、入力するのと同じくらい簡単です:

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

PS:繰り返しは、配列、リスト、セットなどにも機能します


3
assertThat()メソッドは本当に必要ですか?
ceklock

7

JDBCの目的で、コンマで区切られた疑問符のリストを作成する関数が必要だったので、この投稿を見つけました。そこで、2つのバリエーションを使用して、どちらが優れているかを確認することにしました。100万回の反復の後、garden-variety StringBuilderは2秒かかり(fun1)、不可解なおそらく最適なバージョン(fun2)は30秒かかりました。再び謎に包まれることの意味は何ですか?

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

3
2つ目はもっと時間がかかると思います。文字列検索を実行してから、文字列を文字ごとに変更します。
Ethan Heilman、

7

OOPソリューション

ほぼすべての回答が静的関数を解決策として提案していますが、オブジェクト指向(再利用目的と明確化のため)を考えると、CharSequence-Interfaceを介した委任による解決策が思い付きました(これにより、変更可能なCharSequence-Classesの使いやすさが広がります)。

次のクラスはSeparator-String / CharSequenceの有無にかかわらず使用でき、 "toString()"を呼び出すたびに、最後に繰り返される文字列が作成されます。入力/セパレーターはString-Classに限定されるだけでなく、CharSequenceを実装するすべてのクラス(たとえば、StringBuilder、StringBufferなど)にすることができます。

ソースコード:

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

使用例:

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

例-出力:

Repeat=2    Separator=<=    Input=123   Length=3
CharSeq:    Length=8    Val=123<=123
String :    Length=8    Val=123<=123
123ff<=123ff
123ff<====>123ff

4
嫌なものをめったに見たことがない:/
2017年

6

JREクラス(System.arraycopy)のみを使用して、一時オブジェクトの数を最小限に抑えようとすると、次のように記述できます。

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

編集

そしてループなしであなたは試すことができます:

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(", ", "");
}

編集2

コレクションの使用はさらに短くなります:

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

しかし、私はまだ最初のバージョンが好きです。


6
-1:半分に賢すぎます。コードを読み取り可能または効率的にすることを目的とする場合、これらの「ソリューション」はお勧めできません。「繰り返し」は、StringBuilder(初期容量の設定)を使用して簡単に書き換えることができます。そして 'repeat2' / 'repeat3'は本当に非効率的で、String []。toString()によって生成された文字列の未指定の構文に依存します。
スティーブンC

@Thorb:絶対に、このコードでは「メタキャラクター」[]を使用できません
dfa '06

@Stephen:ループを明示的に要求しないように質問が編集されました。私は重複して投稿することを避けるように、AのStringBuilderベースの答えは、すでに提供されました
DFA

@Stephan:私は反対投票を理解できません。私の編集した回答は、必要に応じてループフリーです。効率についての要求はありません。この質問は、ループのない連結を生成するための知的努力にすぎないと思います。
dfa 2009

@Stephan:Collection.toString(およびArrays.toString)を介して生成れた文字列は、AbstractCollection.toStringで明確に指定されています。 「[]」)。隣接する要素は、文字「、」(カンマとスペース)で区切られます。
dfa 2009

6

最短ではありませんが、(私が思うに)最速の方法は、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();
  }

5

速度が問題になる場合は、メモリのコピーをできるだけ少なくする必要があります。したがって、文字の配列を処理する必要があります。

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

速度をテストするために、StirngBuilderを使用した同様の最適な方法は次のとおりです。

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

そしてそれをテストするコード:

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

}

そしてここで私のシステムからの実行結果:

elapsed repeatString: 6006571
elapsed repeatStringSB: 9064937

ループのテストはJITを開始することであり、最適な結果が得られることに注意してください。



3

パフォーマンスが心配な場合は、ループ内でStringBuilderを使用し、ループの終了時に.toString()を実行してください。一体、独自のUtilクラスを作成して再利用してください。最大5行のコード。


2

私はこの質問を本当に楽しんでいます。多くの知識とスタイルがあります。だから私は私のロックンロールを見せずにそれを離れることはできません;)

{
    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);
    }
}

あなたはそれが好きですか?


1
私のより極端なテストでは、-Xms4937mを使用して、1,700,000,000(1.7ギガ)の文字列反復長を生成します
Daniel

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

2

単純なループ

public static String repeat(String string, int times) {
    StringBuilder out = new StringBuilder();
    while (times-- > 0) {
        out.append(string);
    }
    return out.toString();
}

2
timesStringBuilderコンストラクタに渡します。
Behrouz.M、2015年

2

これを試してください:

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

2

再帰を使用すると、次のことができます(三項演算子を使用して、最大1行)。

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

私は知っています、それは醜く、おそらく効率的ではありませんが、それは一行です!


これは私が取るアプローチですが、なぜ必要以上のチェックを行うのですか?戻り値> 0?string + repeat(string、number-1): "";
2018

ああ、niczm25は以下で答えているようです
Fering

@Feringの主な理由により、この方法は常にO(N)ではなくO(log N)になります。他のものよりもわずかに最適化されていますが、それでもなお不十分です。
HyperNeutrino 2018

2

簡単な1行のソリューション:
Java 8が必要

Collections.nCopies( 3, "abc" ).stream().collect( Collectors.joining() );

1

ループを使用したくないという希望にもかかわらず、ループを使用する必要があると思います。

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

forループを使用しない理由はよくありません。あなたの批判に応えて:

  1. どのソリューションを使用しても、ほぼ確実にこれより長くなります。事前に構築された関数を使用すると、より多くのカバーの下でのみ機能します。
  2. あなたのコードを読んでいる誰かは、あなたがその非ループで何をしているのかを理解する必要があります。forループがこれを行う慣用的な方法であることを考えると、forループを使用して行うと、はるかに簡単に理解できます。
  3. はい、誰かが何か賢いものを追加するかもしれませんが、forループ回避することによって、あなた何か賢いことをしています。これは、誤って足で自分を撃たないように意図的に足で自分を撃つようなものです。
  4. 1つずれたエラーも、1つのテストで非常に簡単に検出できます。コードをテストする必要がある場合、off-by-oneエラーは簡単に修正およびキャッチできます。そして、それは注目に値します:上記のコードはオフバイワンエラーを含みません。forループも同じように簡単に修正できます。
  5. したがって、変数を再利用しないでください。これはforループのせいではありません。
  6. 繰り返しになりますが、使用するソリューションはすべて同じです。そして、前に述べたように、バグハンターはおそらくforループでこれを行うことを期待しているので、forループを使用すれば見つけるのが簡単になります。

3
-1。2つの演習を次に示します。a)を使用してコードを実行しますrepetitions = -5。b)Commons LangをダウンロードrepeatString('a', 1000)して、ループで100万回実行します。コードでも同じようにします。時間を比較します。追加のクレジットについては、と同じようにしてくださいrepeatString('ab', 1000)
ChssPly76 09

2
あなたのコードはそれより読みやすいと主張していますStringUtils.repeat("ab",1000)か?それはあなたが反対票を投じたという私の答えだったので。また、パフォーマンスが向上し、バグはありません。
ChssPly76 09

2
引用している質問の2番目の文を読みます。回答後、Andrew Hareの回答に対する明確化として「forループは絶対に避けようとするので」が質問に追加されました。それは重要ではありません。使用どこでも OPの質問に対する答えがありません」。DFAのソリューションでさえ、独創的なものですが、内部のループに使用できます。「jar hell」は上記に返信されました。commons langは、まともなサイズのすべてのアプリケーションで使用されているため、新しい依存関係は追加されません。
ChssPly76 09

2
@ ChssPly76この時点で、私は想像力の専門家がトローリングをしていると確信しています。私が書いたものを誰がどのように読むことができるかを見るのに本当に苦労し、上記で入力した応答を真剣に考えています。
イーサンハイルマン、

1
@ ChssPly76私の答えにはループがまったくありません:-p
fortran

1

出力文字列の長さがわかっているだけで、入力文字列の長さで割り切れない場合は、次の方法を使用します。

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

使用デモ:

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

この場合、望ましい結果を得ることが不可能であるため、空sおよびlength> 0 と一緒に使用しないでください。


0

こちらが最新の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();
    }
    }

これほど大きくする必要はありません。これを作成して、プロジェクトのユーティリティクラスにコピーして貼り付けることができます。

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

したがって、e5、これを行う最善の方法は、上記のコード、またはここでの答えのいずれかを単に使用することだと思います。しかし、それが小さなプロジェクトの場合、コモンズの言語は大きすぎます


他にあなたができることはたくさんあるとは思いません...おそらくAOTに勝るでしょう!!
alexmherrmann、2011

0

私はあなたが望むものと同じことをする再帰的なメソッドを作成しました...これを自由に使ってください...

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

私は上の同じ答え持つ反復配列にJavaですることができます私の乗算の文字列を?


不必要な文字列の再割り当てと再帰オーバーヘッド...悪い、悪い、良くない。
アレクサンダー-モニカを復活させる'30 / 11/16

1
これは遅くなります。推奨されません!StringBuilder代わりに使用してください。
スベトリンナコフ2017年

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.