Cara sederhana untuk mengulang String di java

598

Saya mencari metode atau operator commons sederhana yang memungkinkan saya untuk mengulang beberapa String n kali. Saya tahu saya bisa menulis ini menggunakan for loop, tapi saya ingin menghindari loop kapan pun diperlukan dan metode langsung sederhana harus ada di suatu tempat.

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

repeated.equals("abcabcabc");

Berhubungan dengan:

repeat string javascript Buat NSString dengan mengulangi string lain beberapa kali

Diedit

Saya mencoba untuk menghindari loop ketika mereka tidak sepenuhnya diperlukan karena:

  1. Mereka menambah jumlah baris kode bahkan jika mereka tersimpan di fungsi lain.

  2. Seseorang yang membaca kode saya harus mencari tahu apa yang saya lakukan untuk loop itu. Bahkan jika itu dikomentari dan memiliki nama variabel yang berarti, mereka masih harus memastikan itu tidak melakukan sesuatu yang "pintar".

  3. Programmer suka menempatkan hal-hal yang cerdas dalam loop, bahkan jika saya menulisnya untuk "hanya melakukan apa yang dimaksudkan untuk dilakukan", itu tidak menghalangi seseorang datang dan menambahkan beberapa "perbaikan" pintar pintar.

  4. Mereka seringkali mudah salah. Untuk loop yang melibatkan indeks cenderung menghasilkan off oleh satu bug.

  5. Untuk loop sering menggunakan kembali variabel yang sama, meningkatkan kemungkinan sangat sulit untuk menemukan bug pelingkupan.

  6. Untuk loop meningkatkan jumlah tempat yang harus dicari oleh pemburu bug.

Ethan Heilman
sumber
35
Saya mengerti bahwa untuk loop dapat menyebabkan beberapa masalah nyata. Tetapi Anda tidak boleh mencoba untuk menghindari perulangan "dengan cara apa pun" karena jika itu membuat Anda mudah dibaca, dirawat, dan cepat, Anda menjadi kontraproduktif. Ini merupakan salah satu dari kasus-kasus itu.
Imagist
9
"Mereka menambah jumlah baris kode bahkan jika mereka tersimpan dalam fungsi lain" ... wow, just wow. Big-O, not LoC
Pyrolistic
7
@imagist Saya menghindari loop dalam situasi di mana saya terbaca, dan rawatan. Saya menganggap kecepatan sebagai masalah yang paling tidak penting di sini (sebenarnya bukan masalah). Saya pikir untuk loop terlalu sering digunakan dan saya mencoba untuk belajar hanya menggunakan untuk loop ketika mereka diperlukan dan bukan sebagai solusi default.
Ethan Heilman
3
@ Patrolistik Saya tidak mengklaim kinerja atau manfaat asimptotik. Alih-alih mengatakan bahwa dengan menulis lebih sedikit kode, dan menggunakan fungsi perpustakaan daripada menciptakan kembali roda saya mengurangi area permukaan bug (Lines of Code) sambil meningkatkan keterbacaan. Kedua hal baik itu saya yakin Anda akan setuju.
Ethan Heilman
4
@ e5; maaf karena memposting bertahun-tahun kemudian. Saya merasa pertanyaan ini sangat tepat. Jika disisipkan dalam suatu metode, argumen harus diuji (kali> = 0), kesalahan dilemparkan, dll. Ini menambah kekokohan tetapi juga baris kode untuk dibaca. Mengulang sebuah string adalah sesuatu yang tidak ambigu. Siapa yang membaca kode tahu persis apa yang dilakukan string. Ulangi, bahkan tanpa baris komentar atau javadoc. Jika kita menggunakan perpustakaan yang stabil, masuk akal untuk berpikir bahwa fungsi yang sangat sederhana tidak memiliki bug, BELUM memperkenalkan beberapa bentuk "ketahanan" memeriksa bahwa kita bahkan perlu khawatir. Jika saya bisa meminta 10 perbaikan, ini (semacam) hal-hal akan menjadi satu.
AgostinoX

Jawaban:

230

String::repeat

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

Baru di Java 11 adalah metode String::repeatyang melakukan persis apa yang Anda minta:

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

Javadoc- nya mengatakan:

/**
 * 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
 */ 
Nicolai
sumber
2
@Nicolai kode sumber untuk itu, kalau-kalau ada yang peduli hg.openjdk.java.net/jdk/jdk/file/fc16b5f193c7/src/java.base/…
Eugene
7
Aku bahkan belum melihat java 9 di jalan (dan tidak akan lama ...) - dan 11 tampaknya akan dikirim ..
javadba
1
Mungkin jelas, tetapi Anda dapat memanggil metode ini pada string literal juga:"abc".repeat(3)
Boann
895

Ini adalah versi terpendek (diperlukan Java 1.5+):

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

Di mana nberapa kali Anda ingin mengulangi string dans string untuk mengulang.

Tidak perlu impor atau perpustakaan.

pengguna102008
sumber
22
Saya tidak berpikir itu dikaburkan sama sekali. Tipe primitif ( char[], dalam hal ini) adalah instantiated dengan nulls, kemudian a Stringdibuat dari char[], dan nulls adalah replaced()dengan karakter yang Anda inginkans
Amarok
32
Meskipun ini sangat pintar (+1) Saya pikir itu cukup membuktikan bahwa loop sering membuat kode yang lebih jelas
Richard Tingle
75
Bagi mereka yang mengeluh tentang kebingungan, keterbacaan tergantung pada literasi. Ini sangat jelas dalam hal apa yang dilakukannya dan mendidik bagi mereka yang mungkin tidak langsung melihatnya. Ngomong-ngomong, ini yang Anda dapatkan dengan Java.
dansalmo
11
Untuk kinerja yang lebih baik ...replace('\0', str)harus digunakan daripada versi String.
user686249
11
@ user686249: Hanya ada replace(char oldChar, char newChar)dan replace(CharSequence target, CharSequence replacement)jadi saya tidak melihat bagaimana itu bisa bekerja
user102008
334

Jika Anda menggunakan Java <= 7 , ini sama ringkasnya dengan:

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

Di Java 8 dan di atasnya ada cara yang lebih mudah dibaca:

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

Akhirnya, untuk Java 11 dan di atasnya, ada repeat​(int count)metode baru khusus untuk ini ( tautan )

"abc".repeat(12);

Atau, jika proyek Anda menggunakan perpustakaan java ada lebih banyak pilihan.

Untuk Apache Commons :

StringUtils.repeat("abc", 12);

Untuk Google Guava :

Strings.repeat("abc", 12);
Caner
sumber
4
Yang pertama menyebabkan pengecualian ketika nnol.
saka1029
Contoh java 8 tidak mengkompilasi -> Ketik ketidakcocokan: tidak dapat mengonversi dari Daftar <Character> ke CharSequence
Arigion
6
@Arigion sharuslah String, bukan aChar
Caner
@Caner, terima kasih. Buruk saya, saya minta maaf. Rupanya saya terlalu lelah kemarin. Maaf tentang downvoting. Saya akan menghapus downvote secepat mungkin (diblokir hingga pertanyaan diedit)
Arigion
@Arigion tidak masalah, jelaskan sekarang bahwa s adalah sebuah string
Caner
312

Commons Lang StringUtils.repeat ()

Pemakaian:

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

repeated.equals("abcabcabc");
ChssPly76
sumber
99
menggunakan satu-metode-ketergantungan demi kesederhanaan dalam jangka panjang dapat menghasilkan
gegabah
81
Tentu, kecuali itu milik umum. Saya tidak berpikir saya pernah melihat proyek lebih dari 5000 LOCS yang tidak memiliki commons lang.
Ethan Heilman
11
Commons Lang adalah open source - unduh dan lihat. Tentu saja ada loop di dalamnya, tetapi tidak sesederhana itu. Banyak upaya dilakukan untuk membuat profil dan mengoptimalkan implementasi itu.
ChssPly76
28
Saya tidak menghindari loop karena alasan kinerja (baca alasan saya dalam pertanyaan). Ketika seseorang melihat StringUtils. ulangi, mereka tahu apa yang saya lakukan. Mereka tidak perlu khawatir bahwa saya mencoba untuk menulis versi pengulangan saya sendiri dan membuat kesalahan. Ini adalah unit kognitif atom!
Ethan Heilman
7
@ Thorbjørn Ravn Andersen - ini bisa menjadi BANYAK lebih menarik jika hal-hal terus diambil di luar konteks
ChssPly76
140

Java 8's String.joinmenyediakan cara yang rapi untuk melakukan ini bersama dengan Collections.nCopies:

// say hello 100 times
System.out.println(String.join("", Collections.nCopies(100, "hello")));
Boann
sumber
7
Terima kasih! Untuk android TextUtils.join () dapat digunakan sebagai pengganti String.join ()
MinaHany
2
Terima kasih atas jawaban ini. Tampaknya ini cara paling bersih tanpa menggunakan metode utilitas API oder eksternal! Baik sekali!!
Andreas M. Oberheim
2
Yang menyenangkan tentang metode ini adalah bahwa dengan bergabung Anda dapat memberikan karakter pemisah yang berfungsi sangat berguna jika Anda, katakanlah, membangun daftar CSV. Dengan semua metode lain Anda memiliki karakter bergabung terminating yang perlu dihapus dalam operasi terpisah.
DroidOS
102

Berikut cara untuk melakukannya hanya menggunakan fungsi String standar dan tidak ada loop eksplisit:

// create a string made up of  n  copies of  s
repeated = String.format(String.format("%%%ds", n), " ").replace(" ",s);
IJ Kennedy
sumber
5
Luar biasa :-) Meskipun waspadalah terhadap n menjadi nol ...!
Yang Meyer
4
@ Vijay Dev & fortran: Tidak, maksudnya replace(). Di Java 1.5+, ada versi overload replace()yang memerlukan dua CharSequences (termasuk Strings): download.oracle.com/javase/1.5.0/docs/api/java/lang/…
user102008
79
Aduh. Ini jelek.
Karel Bílek
8
@mzuba katakanlah n=3: pertama-tama memformat string agar terlihat seperti %03d( %%adalah untuk menghindari tanda persentase), yang merupakan kode pemformatan untuk menambahkan 3 angka nol, kemudian memformat 0dengan itu, mengarah ke 000, dan akhirnya mengganti masing 0- masing dengan string
fortran
15
Anda dapat membuat solusinya menjadi lebih jelek dan lebih mudah dipahami: String.format ("% 0" + n + "d", 0) .replace ("0", s)
Artur
87

Jika Anda seperti saya dan ingin menggunakan Google Guava dan bukan Apache Commons. Anda bisa menggunakan metode pengulangan di kelas Guava Strings.

Strings.repeat("-", 60);
Mendongkrak
sumber
2
... dan dapatkan 3Mb dependensi baru.
MonoThreaded
6
@MonoThreaded Saya pikir itu akan pergi tanpa berkata, tetapi jangan menyertakan jambu hanya untuk melakukan pengulangan string. Jawaban saya adalah jika Anda sudah menggunakan jambu biji maka ini adalah bagaimana Anda akan melakukannya.
Jack
53

Dengan , kamu juga bisa menggunakan Stream.generate.

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

dan Anda dapat membungkusnya dengan metode utilitas sederhana jika diperlukan:

public static String repeat(String str, int times) {
   return Stream.generate(() -> str).limit(times).collect(joining());
}
Alexis C.
sumber
6
... atau return IntStream.range(0, times).mapToObj(i -> str).collect(joining());yang memparalelkan lebih baik
Alexis C.
32

Jadi, Anda ingin menghindari loop?

Di sini Anda memilikinya:

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

(tentu saja saya tahu ini jelek dan tidak efisien, tetapi tidak memiliki loop :-p)

Anda ingin itu lebih sederhana dan lebih cantik? gunakan jython:

s * 3

Sunting : mari optimalkan sedikit :-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);
}

Sunting2 : Saya telah melakukan patokan cepat dan kotor untuk 4 alternatif utama, tapi saya tidak punya waktu untuk menjalankannya beberapa kali untuk mendapatkan cara dan merencanakan waktu untuk beberapa input ... Jadi, inilah kode jika ada yang mau untuk mencobanya:

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

Dibutuhkan 2 argumen, yang pertama adalah jumlah iterasi (setiap fungsi dijalankan dengan waktu pengulangan arg dari 1..n) dan yang kedua adalah string untuk diulang.

Sejauh ini, inspeksi cepat terhadap waktu yang berjalan dengan input yang berbeda meninggalkan peringkat seperti ini (lebih baik menjadi lebih buruk):

  1. Tambahkan StringBuilder berulang (1x).
  2. Doakan concatenation log2 rekursif (~ 3x).
  3. Penggambaran linear rekursif linear (~ 30x).
  4. Rangkaian gabungan berulang (~ 45x).

Saya tidak akan pernah menduga bahwa fungsi rekursif lebih cepat daripada forloop: -o

Bersenang-senang (xD opsional).

fortran
sumber
1
+1 untuk rekursi dan jelas-jelas menjadi peretas lisp. Saya tidak berpikir ini sangat tidak efisien juga, rangkaian string bukan warcrime dulu, karena + sebenarnya hanyalah UB stringBuilder. Lihat stackoverflow.com/questions/47605/java-string-concatenation dan schneide.wordpress.com/2009/02/23/… . Saya bertanya-tanya berapa banyak tumpukan itu mendorong dan muncul dari biaya rekursi, atau apakah hotspot mengatasinya. Sungguh berharap saya punya waktu luang untuk membandingkannya. Orang lain mungkin?
Ethan Heilman
@ e5: fortran benar; solusi ini dapat dibuat lebih efisien. Implementasi ini tidak perlu akan membuat StringBuilder baru (dan String baru) untuk setiap rekursi. Masih solusi yang bagus.
merampok
3
@ e5 Saya berharap saya adalah seorang hacker Lisp xD ... Jika saya, saya akan menggunakan fungsi rekursif ekor :-p
fortran
1
Microbenchmarks tidak berfungsi dengan baik di Jawa. Mencoba mengukur kecepatan implementasi Anda seperti itu tidak baik.
ceklock
@tecnotron Saya tahu, tapi tetap saja mereka lebih baik daripada tidak sama sekali ... Dan satu-satunya 'kejutan' adalah sedikit perbedaan antara rangkaian simpul naif dan rekursi linier.
fortran
20

Ini mengandung lebih sedikit karakter daripada pertanyaan Anda

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();
}
Pirolistik
sumber
4
Ini mengandung lebih banyak karakter daripada jawaban saya StringUtils.repeat (str, n).
Ethan Heilman
8
Kecuali Anda sudah menggunakan Apache Commons, jawaban ini jauh lebih mudah - jangan mengunduh perpustakaan lain, termasuk di classpath Anda, pastikan lisensinya kompatibel dengan milik Anda, dll.
Paul Tomblin
7
Tolong, jangan pernah kembali nol - dalam hal ini mengembalikan string kosong, memungkinkan Anda untuk selalu menggunakan nilai yang dikembalikan tidak dicentang. Kalau tidak, apa yang saya sarankan untuk digunakan poster.
Thorbjørn Ravn Andersen
7
Nah, ada tiga cara untuk menangani jika s adalah nol. 1. Lewati kesalahan (return null), 2. Sembunyikan kesalahan (return ""), 3. Lempar NPE. Menyembunyikan kesalahan dan melempar NPE tidak keren, jadi saya melewati kesalahan.
Pyrolistic
1
@EthanHeilman menambahkan nilai 2MB commons-lang3.3.1-sourcesdan Anda tidak sebagus itu lagi;) Tetapi jika seseorang sudah memilikinya commons-lang, saya mendukung jawaban Anda.
TWiStErRob
9

berdasarkan jawaban fortran , ini adalah versi recusive yang menggunakan 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();
}
dfa
sumber
1
pengulangan alih-alih rekursi akan mengurangi # frame tumpukan untuk sejumlah besar pengulangan.
La-comadreja
7

menggunakan Dollar itu sederhana seperti mengetik:

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

PS: ulangi juga berfungsi untuk array, Daftar, Set, dll

dfa
sumber
3
apakah metode assertThat () benar-benar dibutuhkan?
ceklock
7

Saya ingin fungsi untuk membuat daftar tanda tanya yang dibatasi koma untuk keperluan JDBC, dan menemukan posting ini. Jadi, saya memutuskan untuk mengambil dua varian dan melihat mana yang berkinerja lebih baik. Setelah 1 juta iterasi, StringBuilder varietas-taman membutuhkan waktu 2 detik (fun1), dan versi samar yang seharusnya lebih optimal (fun2) memerlukan waktu 30 detik. Apa gunanya menjadi samar lagi?

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);
}
Bob
sumber
3
Saya masuk akal bahwa yang kedua akan memakan waktu lebih lama. Itu melakukan pencarian string dan kemudian memodifikasi karakter string dengan karakter.
Ethan Heilman
7

Solusi OOP

Hampir setiap jawaban mengusulkan fungsi statis sebagai solusi, tetapi dengan memikirkan Object-Oriented (untuk keperluan-penggunaan-ulang dan kejelasan) saya datang dengan Solusi melalui Delegasi melalui CharSequence-Interface (yang juga membuka kegunaan pada CharSequence-Classes yang dapat diubah).

Kelas berikut dapat digunakan baik dengan atau tanpa Separator-String / CharSequence dan setiap panggilan ke "toString ()" membangun String akhir yang diulang. Input / Separator tidak hanya terbatas pada String-Class, tetapi dapat setiap Kelas yang mengimplementasikan CharSequence (mis. StringBuilder, StringBuffer, dll)!

Kode sumber:

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

Contoh-Penggunaan:

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

Contoh-Output:

Repeat=2    Separator=<=    Input=123   Length=3
CharSeq:    Length=8    Val=123<=123
String :    Length=8    Val=123<=123
123ff<=123ff
123ff<====>123ff
Maciej Schuttkowski
sumber
4
jarang saya melihat hal-hal yang menjijikkan: /
Ven
6

hanya menggunakan kelas JRE ( System.arraycopy ) dan mencoba untuk meminimalkan jumlah objek temp Anda dapat menulis sesuatu seperti:

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

dan tanpa loop Anda dapat mencoba:

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

menggunakan Koleksi bahkan lebih pendek:

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

namun saya masih suka versi pertama.

dfa
sumber
6
-1: terlalu pintar setengahnya. Jika tujuan Anda adalah membuat kode Anda mudah dibaca atau efisien, "solusi" ini bukan ide yang baik. 'repeat' hanya dapat ditulis ulang menggunakan StringBuilder (pengaturan kapasitas awal). Dan 'repeat2' / 'repeat3' benar-benar tidak efisien, dan bergantung pada sintaks yang tidak ditentukan dari String yang dihasilkan oleh String []. ToString ().
Stephen C
@ Thorb: tentu saja, dengan kode ini Anda tidak dapat menggunakan "metacharacter", [],
dfa
@Stephen: pertanyaan diedit untuk meminta secara eksplisit tidak ada loop. Sebuah StringBuilder jawaban berdasarkan itu sudah disediakan jadi aku menghindari untuk memasukkan duplikat
DFA
@Stephan: Saya tidak bisa mengetahui downvote. Jawaban saya yang diedit adalah bebas loop saat di-requet. Tidak ada permintaan tentang efisiensi. Saya pikir pertanyaan ini hanyalah upaya intelektual untuk menghasilkan rangkaian tanpa loop.
dfa
@Stephan: String yang dihasilkan melalui Collection.toString (dan Arrays.toString) secara jelas ditentukan dalam AbstractCollection.toString: "Representasi string terdiri dari daftar elemen koleksi dalam urutan mereka dikembalikan oleh iteratornya, tertutup dalam tanda kurung siku ( "[]"). Elemen yang berdekatan dipisahkan oleh karakter "," (koma dan spasi). "
dfa
6

Bukan yang terpendek, tetapi (saya pikir) cara tercepat adalah dengan menggunakan 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();
  }
Simon
sumber
5

Jika kecepatan menjadi perhatian Anda, maka Anda harus menggunakan penyalinan sebanyak mungkin memori. Oleh karena itu diperlukan untuk bekerja dengan array karakter.

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

Untuk menguji kecepatan, metode optimal yang serupa menggunakan StirngBuilder adalah seperti ini:

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

dan kode untuk mengujinya:

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

}

Dan di sini jalankan hasil dari sistem saya:

elapsed repeatString: 6006571
elapsed repeatStringSB: 9064937

Perhatikan bahwa tes untuk loop adalah untuk menendang JIT dan memiliki hasil yang optimal.

Panayotis
sumber
4

demi keterbacaan dan portabilitas:

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

Jika Anda khawatir tentang kinerja, cukup gunakan StringBuilder di dalam loop dan lakukan .toString () saat keluar dari Loop. Heck, tulis Kelas Util Anda sendiri dan gunakan kembali. 5 Baris kode maks.

WolfmanDragon
sumber
2

Saya sangat menikmati pertanyaan ini. Ada banyak pengetahuan dan gaya. Jadi saya tidak bisa meninggalkannya tanpa menunjukkan rock and roll saya;)

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

Apakah kamu menyukainya?

Daniel De León
sumber
1
Dalam pengujian saya yang lebih ekstrem, saya menghasilkan panjang pengulangan string 1.700.000.000 (1,7 gigas) ,, menggunakan -Xms4937m
Daniel De León
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);
}
elang
sumber
2

Lingkaran sederhana

public static String repeat(String string, int times) {
    StringBuilder out = new StringBuilder();
    while (times-- > 0) {
        out.append(string);
    }
    return out.toString();
}
Codler
sumber
2
diteruskan timeske konstruktor StringBuilder.
Behrouz.
2

Coba ini:

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

sumber
2

Dengan menggunakan rekursi, Anda dapat melakukan hal berikut (menggunakan operator ternary, satu baris maksimal):

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

Saya tahu, itu jelek dan mungkin tidak efisien, tetapi satu baris!

HyperNeutrino
sumber
Ini adalah pendekatan yang akan saya ambil tetapi mengapa melakukan lebih banyak pemeriksaan daripada yang dibutuhkan? mengembalikan angka> 0? string + repeat (string, number-1): "";
Fering
Oh, sepertinya niczm25 menjawabnya di bawah ini
Fering
@Mencari alasan utama sehingga cara ini adalah O (log N) rata-rata daripada O (N) selalu. Optimasi sedikit lebih dari yang lain, meskipun masih buruk.
HyperNeutrino
2

solusi langsung satu jalur:
membutuhkan Java 8

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

Meskipun keinginan Anda untuk tidak menggunakan loop, saya pikir Anda harus menggunakan 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();
}

Alasan Anda untuk tidak menggunakan for for bukan alasan yang bagus. Menanggapi kritik Anda:

  1. Solusi apa pun yang Anda gunakan hampir pasti lebih lama dari ini. Menggunakan fungsi yang sudah dibuat sebelumnya hanya melipatnya di bawah lebih banyak penutup.
  2. Seseorang yang membaca kode Anda harus mencari tahu apa yang Anda lakukan dalam non-for-loop itu. Mengingat bahwa for-loop adalah cara idiomatis untuk melakukan ini, akan lebih mudah untuk mengetahui jika Anda melakukannya dengan for for.
  3. Ya seseorang bisa menambahkan sesuatu yang cerdas, tapi dengan menghindari untuk loop Anda sedang melakukan sesuatu yang cerdas . Itu seperti menembak diri sendiri di kaki secara sengaja untuk menghindari menembak kaki sendiri secara tidak sengaja.
  4. Kesalahan satu per satu juga mudah diingat dengan satu tes. Mengingat bahwa Anda harus menguji kode Anda, kesalahan off-by-one seharusnya mudah diperbaiki dan ditangkap. Dan perlu dicatat: kode di atas tidak mengandung kesalahan satu per satu. Untuk loop sama mudahnya untuk mendapatkan yang benar.
  5. Jadi jangan gunakan kembali variabel. Itu bukan kesalahan for-loop.
  6. Sekali lagi, begitu juga solusi apa pun yang Anda gunakan. Dan seperti yang saya perhatikan sebelumnya; pemburu bug mungkin akan mengharapkan Anda untuk melakukan ini dengan for for loop, sehingga mereka akan lebih mudah menemukannya jika Anda menggunakan for for loop.
Imagist
sumber
3
-1. Inilah dua latihan untuk Anda: a) jalankan kode Anda repetitions = -5. b) mengunduh Commons Lang dan menjalankan repeatString('a', 1000)jutaan kali dalam satu lingkaran; lakukan hal yang sama dengan kode Anda; bandingkan waktu. Untuk kredit tambahan lakukan hal yang sama dengan repeatString('ab', 1000).
ChssPly76
2
Apakah Anda berpendapat bahwa kode Anda lebih mudah dibaca StringUtils.repeat("ab",1000)? Karena itu adalah jawaban saya yang telah Anda turunkan. Ini juga berkinerja lebih baik dan tidak memiliki bug.
ChssPly76
2
Baca kalimat ke-2 dalam pertanyaan yang Anda kutip. "Saya mencoba untuk menghindari loop di semua biaya karena" telah ditambahkan ke pertanyaan sebagai klarifikasi dalam menanggapi jawaban Andrew Hare setelah balasan saya - bukan itu penting karena jika posisi yang Anda ambil adalah "jawaban buruk jika loop adalah digunakan di mana saja "tidak ada jawaban untuk pertanyaan OP. Bahkan solusi dfa - inventif apa adanya - gunakan untuk loop di dalamnya. "toples neraka" dijawab di atas; Lagipula, commons lang digunakan dalam setiap aplikasi berukuran layak dan karenanya tidak menambah ketergantungan baru.
ChssPly76
2
@ ChssPly76 pada titik ini saya cukup yakin bahwa imagist sedang trolling. Saya benar-benar kesulitan melihat bagaimana orang dapat membaca apa yang saya tulis dan dengan serius memikirkan tanggapan yang diketik di atas.
Ethan Heilman
1
@ ChssPly76 jawaban saya tidak memiliki loop sama sekali :-p
fortran
1

Jika Anda hanya tahu panjang string output (dan mungkin tidak dapat habis dibagi dengan panjang string input), maka gunakan metode ini:

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

Demo penggunaan:

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

Jangan gunakan dengan kosong sdan length> 0, karena tidak mungkin untuk mendapatkan hasil yang diinginkan dalam kasus ini.

John McClane
sumber
0

di sini adalah Stringutils.java terbaru 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();
    }
    }

bahkan tidak perlu sebesar ini, dapat dibuat menjadi ini, dan dapat disalin dan ditempelkan ke kelas utilitas dalam proyek Anda.

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

Jadi e5, saya pikir cara terbaik untuk melakukan ini adalah dengan menggunakan kode yang disebutkan di atas, atau salah satu jawaban di sini. tetapi commons lang terlalu besar jika itu adalah proyek kecil

alexmherrmann
sumber
Saya tidak berpikir ada banyak hal lain yang dapat Anda lakukan ... excet mungkin AOT !!
alexmherrmann
0

Saya menciptakan metode rekursif yang melakukan hal yang sama seperti yang Anda inginkan .. jangan ragu untuk menggunakan ini ...

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

saya punya jawaban yang sama di Bisakah saya mengalikan string di java untuk mengulangi urutan?

niczm25
sumber
Realokasi string yang tidak perlu, dan overhead rekursi ... buruk, buruk, tidak baik.
Alexander - Reinstate Monica
1
Ini akan lambat. Tidak direkomendasikan! Gunakan StringBuildersebagai gantinya.
Svetlin Nakov
0
public static String rep(int a,String k)

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

Anda dapat menggunakan metode rekursif ini untuk tujuan yang Anda inginkan.

Syed Salman Hassan
sumber