Простой способ повторить строку в Java - PullRequest
509 голосов
/ 05 августа 2009

Я ищу простой метод или оператор, который позволяет мне повторять несколько строк n раз. Я знаю, что мог бы написать это, используя цикл for, но я хочу избегать циклов for всякий раз, когда необходимо, и где-то должен существовать простой прямой метод.

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

repeated.equals("abcabcabc");

Относится к:

повтор строки javascript Создать строку NSSt, повторяя другую строку заданное количество раз

Отредактировано

Я стараюсь избегать циклов, когда они не являются полностью необходимыми, потому что:

  1. Они добавляют к числу строк кода, даже если они спрятаны в другой функции.

  2. Кто-то, читающий мой код, должен выяснить, что я делаю в этом цикле for. Даже если он закомментирован и имеет значимые имена переменных, они все равно должны убедиться, что он не делает ничего «умного».

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

  4. Очень часто их легко ошибиться. Для циклов, включающих индексы, склонны генерировать по одной ошибке.

  5. Поскольку циклы часто используют одни и те же переменные, повышая вероятность того, что действительно трудно найти ошибки определения объема.

  6. Для циклов увеличьте количество мест, которые должен искать охотник за насекомыми.

Ответы [ 28 ]

9 голосов
/ 06 августа 2009

на основе ответа Фортрана , это рекурсивная версия, использующая 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();
}
7 голосов
/ 06 августа 2015

ООП решение

Почти в каждом ответе предлагается статическая функция в качестве решения, но, думая об объектно-ориентированном (для целей повторного использования и ясности), я придумал решение через делегирование через интерфейс CharSequence (который также открывает удобство использования в изменчивом CharSequence Классы).

Следующий класс можно использовать как с, так и без Separator-String / CharSequence, и каждый вызов toString () создает последнюю повторяемую строку. Input / Separator не только ограничен 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
7 голосов
/ 01 февраля 2010

, используя Dollar , просто набрав:

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

PS: повтор работает также для массива, списка, набора и т. Д.

7 голосов
/ 06 декабря 2012

Я хотел, чтобы функция создавала разделенный запятыми список знаков вопроса для целей JDBC, и нашел этот пост. Итак, я решил взять два варианта и посмотреть, какой из них работает лучше. После 1 миллиона итераций садовый сорт 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);
}
6 голосов
/ 05 августа 2009

, используя только классы 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);
}

EDIT

и без петель вы можете попробовать:

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

однако мне все еще нравится первая версия.

5 голосов
/ 19 мая 2017

Если вам важна скорость, вам следует использовать как можно меньше памяти для копирования. Таким образом, требуется работать с массивами символов.

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 голосов
/ 18 апреля 2016

для удобства чтения и переносимости:

public String repeat(String str, int count){
    if(count <= 0) {return "";}
    return new String(new char[count]).replace("\0", str);
}
4 голосов
/ 12 октября 2017

Не самый короткий, но (я думаю) самый быстрый способ - использовать 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();
  }
3 голосов
/ 05 августа 2009

Если вы беспокоитесь о производительности, просто используйте StringBuilder внутри цикла и выполните .toString () при выходе из цикла. Черт возьми, напиши свой собственный класс Util и используй его снова. 5 строк кода макс.

2 голосов
/ 13 ноября 2013

Попробуйте это:

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;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...