在Java中重复字符串的简单方法


597

我在寻找一个简单的方法,公共或操作员,让我再重复一些字符串ñ倍。我知道我可以使用for循环编写此代码,但是我希望在必要时避免for循环,并且应该在某个地方存在一个简单的直接方法。

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

repeated.equals("abcabcabc");

相关:

重复字符串javascript 通过重复给定次数另一个字符串来创建NSString

已编辑

当它们不是完全必要时,我尝试避免for循环,因为:

  1. 即使将它们隐藏在另一个函数中,它们也会增加代码行数。

  2. 读我的代码的人必须弄清楚我在for循环中正在做什么。即使它被注释并且具有有意义的变量名称,他们仍然必须确保它没有做任何“聪明的事情”。

  3. 程序员喜欢将聪明的东西放入for循环中,即使我将其写为“仅按计划执行”,也不排除有人来添加额外的聪明的“修复”。

  4. 它们通常很容易出错。对于涉及索引的循环,往往会产生一个错误。

  5. For循环通常会重用相同的变量,从而增加了很难发现作用域错误的机会。

  6. 对于循环,增加了寻找漏洞猎人的位置。


35
我知道for循环会引起一些实际问题。但是,您不应尝试“不惜一切代价”避免for循环,因为如果这会损害您的可读性,可维护性和速度,那么您将适得其反。这是其中一种情况。
Imagist

9
“即使它们被另一个函数隐藏起来,它们也增加了代码行的数量”……哇,哇。Big-O,而不是LoC
Pyrolistical

7
@imagist我避免在可能会增加可读性和可维护性的情况下进行循环。我认为速度是这里最不重要的问题(实际上不是问题)。我认为for循环已被过度使用,我试图学习仅在必要时才使用for循环,而不是将其作为默认解决方案。
伊桑·海尔曼

3
@Pyrolistical我没有要求性能或渐近收益。而是说,通过编写更少的代码,并使用库函数而不是重新设计轮子,我减少了错误的表面积(代码行),同时提高了可读性。这两件事我都相信你会同意的。
伊桑·海尔曼

4
@ e5;很抱歉,过了几年才发帖。我觉得这个问题很合适。如果插入到方法中,则应测试参数(times> = 0),引发错误等,这不仅增加了健壮性,而且还增加了要读取的代码行。重复一个字符串是明确的。即使没有一行注释或javadoc,读代码的人也完全知道string.repeat的作用。如果我们使用稳定的库,可以认为一个简单的函数没有bug, YET引入了某种形式的“健壮性”检查,我们甚至需要担心。如果我可以提出10项改进,那么(这种)事情就是其中之一。
AgostinoX

Answers:


229

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从中创建a char[],并且null replaced()使用您想要的字符进行创建s
Amarok 2012年

32
尽管这非常聪明(+1),但我认为这足以证明for循环通常使代码更清晰的意义
Richard Tingle

75
对于抱怨混淆的人,可读性取决于读写能力。对于那些可能不会立即看到它的人来说,它的功能和教育意义是非常清楚的。顺便说一下,这就是使用Java所获得的。
dansalmo 2014年

11
为了获得更好的性能,...replace('\0', str)应使用String版本。
user686249 2014年

11
@ user686249:仅存在replace(char oldChar, char newChar)replace(CharSequence target, CharSequence replacement)所以我看不到它如何工作
user102008 2014年

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)一种专门用于this(link)的新方法

"abc".repeat(12);

另外,如果您的项目使用Java库,则还有更多选择。

对于Apache Commons

StringUtils.repeat("abc", 12);

对于Google Guava

Strings.repeat("abc", 12);

4
前者n为零时会导致异常。
saka1029

Java 8示例无法编译->类型不匹配:无法从List <Character>转换为CharSequence
Arigion '17

6
@Arigion s必须是String,而不是Char
Caner

@Caner谢谢。我不好,我很抱歉。昨天我显然太累了。对不起投票。我将尽快删除
下降表决

@Arigion没问题,现在让我们清楚地知道s是一个字符串
Caner

312

公用语言Lang StringUtils.repeat()

用法:

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

repeated.equals("abcabcabc");

99
从长远来看,为了简单起见,使用一种方法依赖关系可能会引起震撼
dfa

81
当然,除了它是公共语言。我认为我从未见过超过5000个LOCS的项目,但没有公共语言。
伊桑·海尔曼

11
Commons Lang是开源的-下载并查看。当然,它内部有一个循环,但并不是那么简单。在剖析和优化该实现上花费了大量精力。
ChssPly76

28
我不会因为性能原因而避免循环(请在问题中阅读我的原因)。当有人看到StringUtils.repeat时,他们知道我在做什么。他们不必担心我试图编写自己的重复版本并犯了错误。它是原子的认知单位!
伊桑·海尔曼

7
@ThorbjørnRavn Andersen-如果事情在上下文之外继续进行,它可能会变得更加有趣
ChssPly76'2009年

140

Java 8 String.join结合以下方法提供了一种简洁的方法Collections.nCopies

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

7
谢谢!对于Android,可以使用TextUtils.join()代替String.join()
MinaHany

2
感谢您的回答。不使用任何外部API oder实用程序方法,这似乎是最干净的方法!很好!!
Andreas M. Oberheim

2
关于此方法的好处是,使用join可以提供分隔符,如果您要建立CSV列表,那么分隔符非常方便。使用所有其他方法,您需要有一个终止连接字符,需要在单独的操作中将其删除。
DroidOS '18 -10-15

102

这是一种仅使用标准String函数且不使用显式循环的方法:

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

5
了不起的:-)尽管要当心n变为零…!
Yang Meyer 2010年

4
@Vijay Dev&fortran:不,他是说replace()。在Java 1.5+,存在的重载版本replace(),它有两个CharSequenceS(包括StringS):download.oracle.com/javase/1.5.0/docs/api/java/lang/...
user102008

79

8
@mzuba让我们说n=3:它首先格式化一个字符串,使其看起来像%03d%%是逃避百分号),这是添加3个填充零的格式化代码,然后对其进行格式化0,导致000,最后用0字符串替换每个
fortran 2013年

15
您可以使解决方案不那么难看,更易于理解:String.format(“%0” + n +“ d”,0).replace(“ 0”,s)
Artur

87

如果您像我一样,并且想使用Google Guava而不是Apache Commons。您可以在Guava Strings类中使用repeat方法。

Strings.repeat("-", 60);

2
...并获得3Mb的新依赖项。
单线程'18

6
@MonoThreaded我认为不用多说,但不要包括番石榴只是为了重复字符串。我的答案是关于您是否已经在使用番石榴,那么这就是您的做法。
杰克

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());更好地并行化
Alexis C.

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个参数,第一个是迭代次数(每个函数的重复时间arg从1..n开始运行),第二个是要重复的字符串。

到目前为止,快速检查使用不同输入的时间可以得出这样的排名(更糟):

  1. 迭代StringBuilder追加(1x)。
  2. 递归串联log2调用(〜3x)。
  3. 递归串联线性调用(〜30x)。
  4. 线性迭代级联(〜45x)。

我永远都不会猜到递归函数比for循环要快:-o

玩的开心(标准xD)。


1
+1递归,显然是轻率的黑客。我也不认为这没有那么低效,字符串连接不再是曾经的问题,因为+确实只是stringBuilder UTH。参见stackoverflow.com/questions/47605/java-string-concatenationschneide.wordpress.com/2009/02/23/… 。我想知道递归成本中所有这些堆栈压入和弹出的次数是多少,还是由热点来解决。真希望我有空闲时间进行基准测试。也许有人吗?
伊桑·海尔曼

@ e5:fortran是正确的;该解决方案可以提高效率。此实现将不必要为每个递归创建一个新的StringBuilder(和一个新的String)。仍然是一个不错的解决方案。

3
@ e5我希望我是一个Lisp黑客xD ...如果是的话,我会使用尾部递归函数:-p
fortran

1
微基准测试在Java中效果不佳。试图像这样衡量实现速度是不好的。
ceklock

我知道@tecnotron,但它们总比没有强。。。唯一的“惊喜”是朴素的循环串联和线性递归之间的细微差别。
fortran 2012年

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的风景,这个答案是少了很多麻烦-没有下载另一个库,其中包括它在类路径,确保其许可证是你的,等兼容
保罗汤布林

7
请永远不要返回null-在这种情况下,请返回一个空字符串,使您可以始终使用未经检查的返回值。否则,我会推荐海报使用的东西。
托尔比约恩Ravn的安德森

7
好吧,有三种方法可以处理s是否为空。1.传递错误(返回null),2.隐藏错误(返回“”),3.抛出NPE。隐藏错误并抛出NPE并不酷,所以我通过了错误。
Pyrolistical

1
@EthanHeilman添加2MB的值,commons-lang3.3.1-sources您再也不是那么好了;)但是,如果有人已经拥有commons-lang,我会支持您的回答。
TWiStErRob

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 2014年

7

使用Dollar就像输入一样简单:

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

PS:对数组,列表,集合等也可以重复使用


3
确实需要assertThat()方法吗?
ceklock

7

我想要一个函数来创建一个逗号分隔的问号列表以用于JDBC,并找到了这篇文章。因此,我决定采用两种变体,看看哪种变体更好。经过一百万次迭代后,各种菜色的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
我认为第二个将花费更长的时间。它正在执行字符串搜索,然后逐个字符地修改字符串。
伊桑·海尔曼

7

OOP解决方案

几乎每个答案都提出一个静态函数作为解决方案,但是考虑到面向对象(出于可重用性和清晰度),我通过CharSequence-Interface通过委托提出了一个解决方案(这也打开了可变CharSequence-Class的可用性)。

可以在有或没有Separator-String / CharSequence的情况下使用以下类,并且对“ toString()”的每次调用都会构建最终的重复String。输入/分隔符不仅限于String-Class,而且可以是实现CharSequence的每个Class(例如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
我很少见到的东西,恶心:/
法师

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

使用Collections更短:

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

但是我仍然喜欢第一个版本。


6
-1:太聪明了。如果您的目标是使代码可读或高效,那么这些“解决方案”不是一个好主意。可以使用StringBuilder(设置初始容量)简单地重写“ repeat”。而'repeat2'/'r​​epeat3'的确效率低下,并且取决于String []。toString()生成的String的未指定语法。
Stephen C

@Thorb:绝对,使用此代码,您不能使用“元字符”,[]
dfa

@Stephen:已对问题进行了编辑,以明确请求无循环。已经提供了基于StringBuilder的答案,因此我避免发布重复的内容
dfa

@斯蒂芬:我不知道那票。我编辑的答案无格无漏。没有关于效率的要求。我认为这个问题只是产生连接而没有循环的智力上的努力
dfa

@Stephan:通过Collection.toString(和Arrays.toString)产生的字符串在AbstractCollection.toString 中明确指定:“字符串表示形式包括一个集合元素的列表,这些元素按其迭代器返回的顺序排列,并用方括号括起来( “ []”)。相邻元素之间用字符“,”(逗号和空格)分隔。
dfa

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并获得最佳结果。


4

为了可读性和可移植性:

public String repeat(String str, int count){
    if(count <= 0) {return "";}
    return new String(new char[count]).replace("\0", str);
}

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
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
传递times给StringBuilder构造函数。
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

使用递归,您可以执行以下操作(使用三元运算符,最多一行):

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):“”;
Fering

哦,似乎niczm25在下面回答了该问题
Fering

@感觉到主要的原因,因此这种方式是O(log N)平均值而不是总是O(N)。尽管仍然很糟糕,但比其他优化稍多一些。
HyperNeutrino

2

一个简单的单行解决方案:
需要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. 一次测试也很容易发现一对一的错误。鉴于您应该测试代码,因此一个容易出错的错误应该易于修复和捕获。值得注意的是:上面的代码不包含一对一的错误。for循环同样容易正确。
  5. 因此,请勿重用变量。那不是for循环的错。
  6. 同样,您使用的任何解决方案也是如此。正如我之前指出的;一个bug猎人可能会期望您使用for循环来执行此操作,因此如果您使用for循环,他们将更容易找到它。

3
-1。这是为您提供的两个练习:a)使用运行代码repetitions = -5。b)下载Commons Lang并repeatString('a', 1000)循环运行一百万次;用你的代码做同样的事情;比较时间。如需额外的积分,请使用repeatString('ab', 1000)
ChssPly76

2
您是否认为自己的代码更具可读性StringUtils.repeat("ab",1000)?因为那是我拒绝您投票的答案。它的性能也更好,没有错误。
ChssPly76

2
阅读您引用的问题中的第二句话。在回答后回答“安德鲁·黑尔”时,在问题中添加了“澄清,我不惜一切代价避免循环,因为这很重要,因为如果您的职位是”在任何地方使用“对OP问题没有答案。甚至dfa的解决方案(即使具有创造性)也用于内部循环。上面回答了“地狱”;无论如何,common lang都会在每个体面的应用程序中使用,因此不会添加新的依赖项。
2009年

2
@ ChssPly76此时,我非常确定imagist正在拖钓。我真的很难看到任何人都可以阅读我写的内容并认真思考上面键入的答案。
伊桑·海尔曼

1
@ ChssPly76我的答案根本没有任何循环:-p
fortran,2009年

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

不要与empty slength> 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 static String rep(int a,String k)

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

您可以针对所需目标使用此递归方法。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.