Java bir dize tekrarlamak için basit bir yol


597

Basit bir ortak yöntem veya operatör bana bazı dize n kez tekrarlamak için arıyorum . Bunu bir for döngüsü kullanarak yazabileceğimi biliyorum, ancak gerektiğinde döngülerden kaçınmak istiyorum ve bir yerde basit bir doğrudan yöntem olmalı.

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

repeated.equals("abcabcabc");

İle ilgili:

string string javascript'i başka bir dizeyi belirli sayıda tekrarlayarak NSString oluşturun

Düzenlenen

Tamamen gerekli olmadığında döngülerden kaçınmaya çalışırım çünkü:

  1. Başka bir işlevde sıkışmış olsalar bile kod satırlarının sayısını eklerler.

  2. Kodumu okuyan biri döngü için ne yaptığımı bulmak zorunda. Yorumlanmış ve anlamlı değişken isimlerine sahip olsa bile, yine de "akıllı" bir şey yapmadığından emin olmak zorundadırlar.

  3. Programcılar döngüler için zekice şeyler koymayı çok severler, bunu "sadece yapmayı amaçladığı şeyi yap" yazsa bile, bu birisinin gelmesini ve ek zekice "düzeltme" eklemesini engellemez.

  4. Yanlış anlaşılmaları çok kolaydır. Endeksleri içeren döngüler bir hata tarafından ortaya çıkma eğilimindedir.

  5. Döngüler genellikle aynı değişkenleri yeniden kullanır ve kapsam belirleme hataları bulma şansını artırır.

  6. Döngüler için bir böcek avcısının bakması gereken yer sayısını arttırın.


35
Döngüler için bazı gerçek sorunlara neden olabileceğini anlıyorum. Ancak döngülerden "her ne pahasına olursa olsun" kaçınmaya çalışmamalısınız, çünkü eğer okunabilirlik, bakım kolaylığı ve hıza mal oluyorsa, üretken olmuyorsunuzdur. Bu, o davalardan biri.
Imagist

9
“Başka bir fonksiyona sıkışmış olsalar bile kod satırlarının sayısını arttırıyorlar” ... vay, sadece vay. Big-O, LoC değil
Pyrolistics

7
@imagist Bana okunabilirlik ve bakım kolaylığı sağlayan durumlarda döngülerden kaçınıyorum. Hızı burada en önemli sorun olarak görüyorum (aslında sorun değil). Döngüler için aşırı kullanıldığını düşünüyorum ve varsayılan bir çözüm olarak değil, yalnızca gerektiğinde döngüler için kullanmayı öğrenmeye çalışıyorum.
Ethan Heilman

3
@Pyrolistik Performans veya asimtotik faydalar talep etmiyorum. Bunun yerine, daha az kod yazarak ve tekerleği yeniden icat etmek yerine kütüphane fonksiyonlarını kullanarak okunabilirliği arttırırken böcek yüzey alanını (Kod Satırları) azalttığımı söylerim. Hem iyi şeyler hem de eminim.
Ethan Heilman

4
@ e5; yıllar sonra yayınladığım için özür dilerim.Bu soruyu bu kadar uygun buluyorum. Bir yönteme eklenirse, bağımsız değişkenler test edilmeli (times> = 0), atılan hatalar vb. Bu sağlamlık ve okunacak kod satırları eklemelidir. Bir dizeyi tekrarlamak açık bir şeydir.Kodu okuyanlar, bir yorum satırı veya javadoc olmasa bile, bir string.repeat öğesinin ne yaptığını tam olarak bilir. YET, endişelenmemiz gereken bir tür "sağlamlık" kontrolü sunar. 10 iyileştirme isteyebilirsem, bu (bir tür) şeylerden biri olurdu.
AgostinoX

Yanıtlar:


229

String::repeat

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

Java 11'de yeni yöntemString::repeat , tam olarak istediğinizi :

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

Onun Javadoc diyor ki:

/**
 * 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 henüz sokakta görmedim (ve uzun bir süre için olmayacak ..) - ve 11 görünüşe göre gemi için ayarlanmış ..
javadba

1
Muhtemelen açıktır, ancak bu yöntemi bir dizgi değişmezinde de "abc".repeat(3)
çağırabilirsiniz

895

İşte en kısa sürüm (Java 1.5+ gereklidir):

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

Nerede n kaç kez tekrarlamak istediğiniz ves .

İçe aktarma veya kütüphane gerekmez.


22
Hiç şaşırmış olduğunu sanmıyorum. İlkel türler ( char[]bu durumda) null'larla somutlaştırılır, sonra a'dan Stringoluşturulur char[]ve null'lar replaced()istediğiniz karakterdedirs
Amarok

32
Bu çok zeki olsa da (+1) Bence döngüler için genellikle daha net kod yapmak için gereken noktayı kanıtlıyor
Richard Tingle

75
Gizleme konusunda şikayet edenler için okunabilirlik okuryazarlığa bağlıdır. Bu, yaptıklarında mükemmel bir şekilde açıktır ve hemen görmeyenler için eğitici. Bu arada Java ile elde edeceğiniz şey budur.
dansalmo

11
Daha iyi performans ...replace('\0', str)için Dize sürümü yerine kullanılmalıdır.
user686249

11
@ user686249: Sadece var replace(char oldChar, char newChar)ve replace(CharSequence target, CharSequence replacement)bu yüzden nasıl çalıştığını göremiyorum
user102008

334

Eğer kullanıyorsanız Java <= 7 as it gets, bu "Özlü" olduğu gibi:

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

In Java 8 ve üzeri daha anlaşılabilir bir yol vardır:

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

Son olarak, Java 11 ve üstü repeat​(int count)için özellikle bunun için yeni bir yöntem var ( bağlantı )

"abc".repeat(12);

Alternatif olarak, projeniz java kütüphaneleri kullanıyorsa daha fazla seçenek vardır.

For Apache Commons :

StringUtils.repeat("abc", 12);

For Google Guava :

Strings.repeat("abc", 12);

4
Birincisi nsıfır olduğunda bir istisna oluşturur .
saka1029

Java 8 örneği derlemiyor
Arigion

6
@Arigion bir sdize olmalı, değilChar
Caner

@Caner Teşekkürler. Benim hatam, özür dilerim. Görünüşe göre dün çok yorgundum. Downvoting için üzgünüm. En kısa sürede aşağı oyu kaldıracağım (soru düzenlenene kadar engellendi)
Arigion

@ Sorun yok, şimdi s bir dize olduğunu açıkladı
Caner

312

Commons Lang StringUtils.repeat ()

Kullanımı:

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

repeated.equals("abcabcabc");

99
basitlik uğruna uzun vadede tek yönteme bağımlılık kullanmak bir kavanoz cehennemine yol açabilir
dfa

81
Tabii, sadece müşterek lang hariç. Müşterek dilleri olmayan 5000'den fazla LOCS projesi gördüğümü hiç sanmıyorum.
Ethan Heilman

11
Commons Lang açık kaynak - indirin ve bir göz atın. Tabii ki içinde bir döngü var, ama o kadar basit değil. Bu uygulamanın profillenmesi ve optimize edilmesi için çok çaba harcandı.
ChssPly76

28
Performans nedeniyle döngülerden kaçınmam (sorudaki nedenlerimi okuyun). Birisi StringUtils.repeat gördüğünde, ne yaptığımı biliyorlar. Kendi tekrar versiyonumu yazmaya çalıştığım için endişelenmek zorunda değiller ve hata yaptım. Atomik bir bilişsel birim!
Ethan Heilman

7
@ Thorbjørn Ravn Andersen - işler bağlamdan çıkarılmaya devam ederse çok daha ilginç olabilir
ChssPly76

140

Java String.join8'ler, aşağıdakilerle birlikte bunu yapmak için düzenli bir yol sağlar Collections.nCopies:

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

7
teşekkür ederim! Android için TextUtils.join () yerine String.join () kullanılabilir
MinaHany

2
Bu cevap için teşekkürler. Herhangi bir harici API veya yardımcı program yöntemi kullanmadan en temiz yol gibi görünüyor! çok iyi!!
Andreas M. Oberheim

2
Bu yöntemle ilgili güzel şey, bir CSV listesi oluşturuyorsanız, birleştirme ile çok kullanışlı olması için çalışan bir ayırıcı karakter sağlayabilmenizdir. Diğer tüm yöntemlerde, ayrı bir işlemde çıkarılması gereken sonlandırma birleştirme karakterine sahipsiniz.
DroidOS

102

İşte sadece standart Dize işlevlerini kullanarak ve açık döngüler olmadan bunu yapmanın bir yolu:

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

5
İnanılmaz :-) Her ne kadar n sıfır olma sakının…!
Yang Meyer

4
@Vijay Dev & fortran: Hayır, demek istedi replace(). Java 1.5+ sürümünde, aşırı yüklü bir sürümü replace()iki CharSequences alır ( Strings dahil ): download.oracle.com/javase/1.5.0/docs/api/java/lang/…
user102008

79
Ahh. Bu çirkin.
Karel Bílek

8
@mzuba diyelim n=3: İlk biçimleri bir dize göz şey gibi %03d( %%3 dolgu ardından sıfır, biçimini eklemeyi biçimlendirme koddur, yüzde işareti kaçmak etmektir) 0giden, bunda 000ve nihayet her yerini 0dizeleriyle
fortran

15
Çözümü daha az çirkin ve anlaşılmasını kolaylaştırabilirsiniz: String.format ("% 0" + n + "d", 0) .replace ("0", s)
Artur

87

Benim gibiyseniz ve Apache Commons yerine Google Guava'yı kullanmak istiyorsanız. Guava Strings sınıfında yineleme yöntemini kullanabilirsiniz .

Strings.repeat("-", 60);

2
... ve 3Mb yeni bağımlılıklar edinin.
MonoDişli

6
@MonoThreaded Ben söylemeden gideceğini düşündüm, ama sadece bir dize tekrar yapmak için guava dahil etmeyin. Cevabım zaten zaten guava kullanıyorsanız o zaman böyle yapardı.
Jack

53

İle , kullanabilirsiniz Stream.generate.

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

ve gerekirse basit bir yardımcı program yöntemiyle sarabilirsiniz:

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

6
... ya return IntStream.range(0, times).mapToObj(i -> str).collect(joining());da daha iyi paralel olan
Alexis C.

32

Yani döngülerden kaçınmak mı istiyorsunuz?

Bu artık senin:

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

(tabii ki bunun çirkin ve verimsiz olduğunu biliyorum, ama döngüler yok :-p)

Daha basit ve güzel mi istiyorsun? jython kullanın:

s * 3

Düzenleme : biraz optimize edelim :-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 ana alternatif için hızlı ve kirli bir kıyaslama yaptım, ancak araçları almak ve birkaç girdi için zamanları çizmek için birkaç kez çalıştırmak için zamanım yok ... Yani kimse isterse kod dene:

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üman alır, ilki yineleme sayısıdır (her fonksiyon 1..n tekrar süreleri arg ile çalışır) ve ikincisi tekrarlanacak dizedir.

Şimdiye kadar, farklı girdilerle çalışan zamanların hızlı bir şekilde incelenmesi, sıralamayı şu şekilde bırakıyor (daha iyiden kötüye):

  1. Yinelemeli StringBuilder eki (1x).
  2. Özyinelemeli birleştirme log2 çağrıları (~ 3x).
  3. Yinelemeli birleştirme doğrusal çağrıları (~ 30x).
  4. Yinelemeli birleştirme doğrusal (~ 45x).

Ben özyinelemeli işlev fordöngü daha hızlı olduğunu hiç tahmin etmem : -o

İyi eğlenceler (ctional xD).


1
Özyineleme ve açıkçası bir lisp hacker olmak için +1. Bu ya da verimsiz olduğunu sanmıyorum, dize birleştirme bir kez olduğu savaş suçu değil, çünkü + gerçekten sadece bir stringBuilder UTH. Bkz. Stackoverflow.com/questions/47605/java-string-concatenation ve schneide.wordpress.com/2009/02/23/… . Tüm bu yığının özyineleme maliyetinden ne kadar ittiğini ve patladığını veya sıcak noktanın bunlarla ilgilenip ilgilenmediğini merak ediyorum. Gerçekten ben kıyaslamak için boş zaman olsaydı. Belki başka biri?
Ethan Heilman

@ e5: fortran haklı; bu çözüm daha verimli hale getirilebilir. Bu uygulama gereksiz yere her özyineleme için yeni bir StringBuilder (ve yeni bir String) oluşturur. Yine de güzel bir çözüm.
soymak

3
@ e5 Keşke bir Lisp hacker xD olsaydım ... Eğer olsaydım, bir kuyruk özyinelemeli işlev kullanırdım :-p
fortran

1
Mikrobenç işaretleri Java'da iyi çalışmaz. Bunun gibi uygulamalarınızın hızını ölçmeye çalışmak iyi değildir.
ceklock

@tecnotron Biliyorum, ama yine de hiç yoktan iyidirler ... Ve tek 'sürpriz', saf döngü birleştirme ve doğrusal özyineleme arasındaki küçük farktı.
fortran

20

Bu, sorunuzdan daha az karakter içeriyor

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
Cevabım StringUtils.repeat (str, n) 'den daha fazla karakter içeriyor.
Ethan Heilman

8
Zaten Apache Commons kullanmıyorsanız, bu cevap çok daha az zahmetlidir - sınıf yolunuz da dahil olmak üzere başka bir kütüphane indirmenize gerek yoktur, lisansının sizinkilerle uyumlu olduğundan emin olun.
Paul Tomblin

7
Lütfen, asla null döndürmeyin - bu durumda boş bir dize döndürerek döndürülen değeri her zaman işaretlemeden kullanmanıza izin verin. Aksi takdirde, posterin kullanılmasını tavsiye ederim.
Thorbjørn Ravn Andersen

7
Peki, s boşsa, üç yol vardır. 1. Hatayı iletin (return null), 2. Hatayı gizleyin ("" return), 3. Bir NPE atın. Hatayı gizlemek ve bir NPE atmak hoş değil, bu yüzden hatayı geçtim.
Pyrolistics

1
@EthanHeilman 2MB değerinde ekliyor commons-lang3.3.1-sourcesve artık o kadar da iyi değilsin;) Ama birisi zaten varsa commons-lang, cevabınızı destekliyorum.
TWiStErRob

9

fortran'ın cevabına dayanarak , bu bir StringBuilder kullanan tekrarlayan bir versiyon:

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
özyineleme yerine döngü, çok sayıda tekrar için yığın karelerinin sayısını azaltır.
La-comadreja

7

kullanarak Doları yazarak kadar basittir:

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

PS: tekrar dizi, Liste, Set, vb için de çalışır


3
() yöntemi gerçekten gerekli mi?
ceklock

7

JDBC amaçları için virgülle ayrılmış bir soru işareti listesi oluşturmak için bir işlev istedim ve bu gönderiyi buldum. Bu yüzden iki varyantı almaya ve hangisinin daha iyi performans gösterdiğine karar verdim. 1 milyon yinelemeden sonra, bahçe çeşidi StringBuilder 2 saniye (fun1) aldı ve şifreli olduğu söylenen daha uygun versiyon (fun2) 30 saniye sürdü. Yine şifreli olmanın anlamı nedir?

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
İkincisinin çok daha uzun süreceği mantıklı. Bir dize araması gerçekleştirir ve sonra dize karakterini karaktere göre değiştirir.
Ethan Heilman

7

OOP Çözümü

Neredeyse her cevap bir çözüm olarak statik bir işlev öneriyor, ancak Nesne Odaklı (yeniden kullanılabilirlik amaçları ve netlik için) düşünerek CharSequence-Interface (aynı zamanda değişebilir CharSequence-Sınıflarında kullanılabilirliği de açıyor) aracılığıyla Delegasyon aracılığıyla bir Çözüm buldum.

Aşağıdaki Sınıf, Separator-String / CharSequence ile veya bu komut olmadan kullanılabilir ve her "toString ()" çağrısı son tekrarlanan Dizeyi oluşturur. Girdi / Ayırıcı yalnızca String-Class ile sınırlı değildir, aynı zamanda CharSequence'ı uygulayan her bir Sınıf da olabilir (örneğin StringBuilder, StringBuffer, vb.)!

Kaynak kodu:

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

Kullanım-Örnek:

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

Örnek-Çıkış:

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

4
nadiren iğrenç şeyler gördüm: /
Ven

6

yalnızca JRE sınıflarını ( System.arraycopy ) kullanarak ve aşağıdaki gibi bir şey yazabileceğiniz geçici nesne sayısını en aza indirmeye çalışarak :

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

DÜZENLE

ve döngüler olmadan deneyebilirsiniz:

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

DÜZENLEME 2

Koleksiyonlar kullanmak daha da kısadır:

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

ancak yine de ilk sürümü beğendim.


6
-1: yarı yarıya çok akıllı. Amacınız kodu okunabilir veya verimli hale getirmekse, bu "çözümler" iyi bir fikir değildir. 'yineleme' bir StringBuilder kullanılarak yeniden yazılabilir (başlangıç ​​kapasitesinin ayarlanması). Ve 'repeat2' / 'repeat3' gerçekten verimsizdir ve String [] tarafından üretilen Dizenin belirtilmemiş sözdizimine bağlıdır.
Stephen C

@Thorb: kesinlikle, bu kodla "metacharacter", [],
dfa

@Stephen: soru açıkça hiçbir döngü istemeyecek şekilde düzenlendi . Bir StringBuilder tabanlı cevap zaten sağlanmıştı bu yüzden bir yinelenen sonrası
kaçındım

@Stephan: Aşağı oyu bulamıyorum. Düzenlediğim yanıtı gerektiği gibi devre dışı bırakıyorum. Verimlilik ile ilgili herhangi bir talep yok. Bence bu soru sadece bir döngü olmadan birleşme üretmek için entelektüel bir çaba .
dfa

@Stephan: Collection.toString (ve Arrays.toString) aracılığıyla üretilen dize , AbstractCollection.toString'de açıkça belirtilir : "Dize temsili, koleksiyon öğelerinin, köşeli parantez içinde döndürülen sırayla döndürülen sırayla ( "[]"). Bitişik öğeler "," (virgül ve boşluk) karakterleriyle ayrılır.
dfa

6

En kısa değil, ama (sanırım) en hızlı yolu StringBuilder kullanmaktır:

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

Hız endişenizse, mümkün olduğunca daha az bellek kopyalaması kullanmalısınız. Bu nedenle karakter dizileri ile çalışmak gerekir.

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

Hızı test etmek için StirngBuilder kullanan benzer bir optimal yöntem şöyledir:

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

ve test etmek için kod:

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

}

Ve burada sistemimin çalışma sonuçları:

elapsed repeatString: 6006571
elapsed repeatStringSB: 9064937

Döngü testinin JIT'e girmesi ve en iyi sonuçları alması gerektiğini unutmayın.


4

okunabilirlik ve taşınabilirlik uğruna:

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

3

Performans konusunda endişeleriniz varsa, döngü içinde bir StringBuilder kullanın ve Loop'un çıkışında bir .toString () işlemi yapın. Heck, kendi Util Sınıfını yaz ve tekrar kullan. 5 Kod satırı maks.


2

Bu sorudan gerçekten zevk alıyorum. Çok fazla bilgi ve stil var. Bu yüzden rock and roll'umu göstermeden bırakamam;)

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

Sevdin mi?


1
Daha uç testimde 1.700.000.000 (1.7 gigas) dize tekrar uzunluğu üretiyorum, -Xms4937m kullanarak
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);
}

2

Basit döngü

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

2
geçmesi timesStringBuilder yapıcısına.
Behrouz.M

2

Şunu deneyin:

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

Özyineleme kullanarak aşağıdakileri yapabilirsiniz (üçlü operatörler kullanarak, en fazla bir satır):

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

Biliyorum, çirkin ve muhtemelen verimli değil, ama bir satır!


Bu yaklaşım benim alacağım ama neden gerekenden daha fazla kontrol yapıyor? dönüş numarası> 0? string + repeat (dize, sayı-1): "";
Fering

Ah, aşağıda onunla cevap niczm25 görünüyor
Fering

@Bu nedenle, bu yol her zaman O (N) yerine O (log N) ortalaması olur. Yine de kötü olsa da, diğerinden biraz daha fazla optimizasyon.
HyperNeutrino

2

kolay tek satırlık bir çözüm:
Java 8 gerektirir

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

1

Döngüler kullanmama arzunuza rağmen, bence bir döngü kullanmalısınız.

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 döngüsü kullanmamanızın nedenleri iyi değildir. Eleştirilerinize yanıt olarak:

  1. Hangi çözümü kullanırsanız kullanın bundan kesinlikle daha uzun olacaktır. Önceden oluşturulmuş bir işlevi kullanmak, onu yalnızca daha fazla kapağın altına sokar.
  2. Kodunuzu okuyan birisinin, bu döngü olmayan ortamda ne yaptığınızı bulması gerekir. Bir for-loop'un bunu yapmanın deyimsel yolu olduğu göz önüne alındığında, for for döngüsüyle yapıp yapmadığınızı anlamak çok daha kolay olacaktır.
  3. Evet birileri akıllıca bir şey eklemek, ama döngü için kaçınarak olabilir sen edilir akıllıca bir şey yapıyor . Kendinizi yanlışlıkla ayağınızı vurmamak için kasıtlı olarak ayağa vurmak gibidir.
  4. Tek tek hataları da tek bir testle yakalamak çok kolay. Kodunuzu test etmeniz gerektiği göz önüne alındığında, tek tek bir hatanın düzeltilmesi ve yakalanması kolay olmalıdır. Ve dikkat çekmeye değer: yukarıdaki kod birer birer hata içermiyor. Döngüler için doğru şekilde eşit derecede kolaydır.
  5. Yani değişkenleri tekrar kullanmayın. Bu for-loop'un hatası değil.
  6. Yine, hangi çözümü kullanırsanız kullanın. Ve daha önce de belirttiğim gibi; bir böcek avcısı muhtemelen bunu bir for döngüsü ile yapmanızı bekler, bu yüzden bir for döngüsü kullanırsanız onu bulmak daha kolay olur.

3
-1. İşte size iki alıştırma: a) kodunuzu çalıştırın repetitions = -5. b) Commons Lang'ı indirin ve repeatString('a', 1000)bir döngüde milyon kez çalıştırın ; aynısını kodunuzla yapın; zamanları karşılaştırır. Ekstra kredi için aynısını yapın repeatString('ab', 1000).
ChssPly76

2
Kodunuzun daha okunabilir olduğunu StringUtils.repeat("ab",1000)mu düşünüyorsunuz? Çünkü benim cevabımı reddetmiştin. Ayrıca daha iyi performans gösterir ve hiçbir hatası yoktur.
ChssPly76

2
Alıntıladığınız sorudaki 2. cümleyi okuyun. "Her ne pahasına olursa olsun döngülerden kaçınmaya çalışıyorum çünkü" cevabımdan sonra Andrew Hare'nin cevabına yanıt olarak bir açıklama olarak soruna eklendi - önemli değil, çünkü aldığınız pozisyon ise "döngü kötü ise cevap kötüdür kullanılan her yerde OP soruya hiç cevap vardır ". DFA'nın çözümleri - oldukları gibi yaratıcı - bile içerideki döngüler için kullanılır. "jar cehennem" yukarıda yanıtlandı; commons lang zaten her büyüklükteki uygulamada kullanılır ve bu nedenle yeni bir bağımlılık eklemez.
ChssPly76

2
@ ChssPly76 bu noktada imagist trolling eminim. Herkesin yazdıklarımı nasıl okuyabildiğini ve yukarıda yazılan cevapları ciddiye aldığını görmekte gerçekten zorlanıyorum.
Ethan Heilman

1
@ ChssPly76 Cevaplarımın hiç döngüsü yok :-p
fortran

1

Yalnızca çıkış dizesinin uzunluğunu biliyorsanız (ve giriş dizesinin uzunluğuna bölünemeyebilir), bu yöntemi kullanın:

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

Kullanım demosu:

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

Boş sve length> 0 ile kullanmayın , çünkü bu durumda istenen sonucu elde etmek imkansızdır.


0

İşte en son 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();
    }
    }

bu kadar büyük olması bile gerekmez, bunun için yapılabilir ve projenizdeki bir yardımcı program sınıfına kopyalanabilir ve yapıştırılabilir.

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

Yani e5, bunu yapmanın en iyi yolunun sadece yukarıda belirtilen kodu veya cevapların herhangi birini kullanmak olduğunu düşünüyorum. ama müşterek dil küçük bir proje ise çok büyük


Yapabileceğiniz başka çok şey olduğunu sanmıyorum ... belki AOT belki!
alexmherrmann

0

İstediğiniz şeyi yapan özyinelemeli bir yöntem oluşturdum .. Bunu kullanmaktan çekinmeyin ...

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

Ben aynı cevabı var Ben dizileri tekrarlamak için Java dizeleri çarpabilir miyim?


Gereksiz dize yeniden tahsisi ve özyineleme yükü ... kötü, kötü, iyi değil.
Alexander - Monica'yı yeniden

1
Bu yavaş olacak. Tavsiye edilmez! StringBuilderBunun yerine kullanın .
Svetlin Nakov

0
public static String rep(int a,String k)

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

Bu özyinelemeli yöntemi istediğiniz hedef için kullanabilirsiniz.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.