C # 'da bir karakteri tekrar etmenin en iyi yolu


814

\tC # 's bir dizi oluşturmak için en iyi yolu nedir

C # öğreniyorum ve aynı şeyi söylemenin farklı yollarını deniyorum.

Tabs(uint t)bir fonksiyonu olduğu döner bir stringile tmiktarı \t's

Örneğin Tabs(3)iadeler"\t\t\t"

Bu üç uygulama yolundan hangisi Tabs(uint numTabs)en iyisidir?

Tabii ki bu "en iyi" nin ne anlama geldiğine bağlıdır.

  1. LINQ sürümü sadece iki satır, bu güzel. Ancak Tekrarlama ve Toplama çağrıları gereksiz yere zaman / kaynak tüketiyor mu?

  2. StringBuilderVersiyon çok açıktır ama StringBuildersınıf nedense daha yavaş?

  3. stringVersiyon bunu anlamak kolaydır anlamına gelen temeldir.

  4. Hiç önemi yok mu? Hepsi eşit mi?

Bunlar C # için daha iyi bir fikir edinmeme yardımcı olacak sorular.

private string Tabs(uint numTabs)
{
    IEnumerable<string> tabs = Enumerable.Repeat("\t", (int) numTabs);
    return (numTabs > 0) ? tabs.Aggregate((sum, next) => sum + next) : ""; 
}  

private string Tabs(uint numTabs)
{
    StringBuilder sb = new StringBuilder();
    for (uint i = 0; i < numTabs; i++)
        sb.Append("\t");

    return sb.ToString();
}  

private string Tabs(uint numTabs)
{
    string output = "";
    for (uint i = 0; i < numTabs; i++)
    {
        output += '\t';
    }
    return output; 
}

Yanıtlar:


1491

Peki buna ne dersin:

string tabs = new String('\t', n);

Dizeyi nkaç kez tekrarlamak istediğinizdir.

Ya da daha iyisi:

static string Tabs(int n)
{
    return new String('\t', n);
}

2
bunu bir kelime için tekrarlamanın bir yolu var mı? '\ t' yerine "zaman" nasıl kullanılır
asdfkjasdfjk

6
@ user1478137 Veya, daha iyi (ayrıca aşağı): bu
Xynariz

161
string.Concat(Enumerable.Repeat("ab", 2));

İadeler

"Abab"

Ve

string.Concat(Enumerable.Repeat("a", 2));

İadeler

"Aa"

dan ...

.Net içinde dize veya karakter yinelemek için yerleşik bir işlev var mı?


1
Linq olmadan ve yaparak daha iyi hale getirin StruingBuilder!
Bitterblue

4
'' StringBuilder '' mutlaka daha hızlı değildir stackoverflow.com/questions/585860/…
Schiavini

6
Daha hızlı olmayabilir, ancak öndeki doğru kapasiteyi belirlerseniz bellek ayırmalarından (basınç) tasarruf edebilir ve bu, bunu profillemenin mikro ölçütü kadar önemli olabilir.
wekempf

1
var strRepeat = string.Concat (Numaralandırılabilir Tekrar ("ABC", 1000000)); // 50ms
yongfa365

1
@Pharap string.Join, örnekte boşluk ayırıcı kullandıkları için daha hızlıydı. string.Concatsınırlayıcı olmadığında uygundur.
Carter Medlin

124

.NET'in tüm sürümlerinde, bir dizeyi şu şekilde tekrarlayabilirsiniz:

public static string Repeat(string value, int count)
{
    return new StringBuilder(value.Length * count).Insert(0, value, count).ToString();
}

Bir karakteri tekrarlamak new String('\t', count)en iyi seçenektir. Bkz @CMS tarafından cevap .


7
Bu, String için açık ara en hızlı performans. Diğer yöntemler çok fazla ek yük oluşturur.
midspace

@midspace Diğer yanıtların neden daha kötü olduğunu açıklayan var mı biliyor musunuz? Yerel String.Concat dahili olarak StringBuilder gibi optimize olurdu
Marie

@ Marie Aşağıdaki makalede bazı değerlere değinilmiştir. support.microsoft.com/en-au/help/306822/… Aksi takdirde, diğer iki faktör vardır: StringBuilder dizelere izin verir ve yalnızca bir karakterle (orijinal soru ile ilgili olmasa da) ve dizeyle sınırlı değildir. Yukarıdaki concat yanıtı önce Enumerable.Repeat kullanarak bir dizi oluşturmak zorundadır. Dediğim gibi, gereksiz ek yük.
midspace

Ben sadece bir öğe öğeyi yineleme çünkü ilk dizi oluşturmak olmaz varsaymıştı. Bağlantı için teşekkür ederim, bir okuma vereceğim!
Marie

63

En iyi sürüm kesinlikle yerleşik yolu kullanmaktır:

string Tabs(int len) { return new string('\t', len); }

Diğer çözümlerden en kolay olanı tercih edin; ancak bu çok yavaş oluyorsa, daha verimli bir çözüm için çaba gösterin.

A StringBuilderve sonuç uzunluğunu önceden biliyorsanız, aynı zamanda uygun bir kurucu da kullanırsanız, bu çok daha verimlidir, çünkü bu sadece bir zaman alıcı tahsisin gerçekleştiği ve verilerin gereksiz kopyalanması olmadığı anlamına gelir. Saçma: elbette yukarıdaki kod daha verimlidir.


12
sb.Append ('\ t', len);
dan-gph

7
new string('\t', len)Testlerim StringBuilderyaklaşımdan 2x ila 7x daha hızlı gösteriyor . Sizce StringBuilderbu durumda neden daha verimli?
StriplingWarrior

6
@StriplingWarrior Bunu düzelttiğiniz için teşekkürler (iki yıl boyunca burada durduktan sonra, daha az değil!).
Konrad Rudolph

51

Genişletme yöntemleri:

public static string Repeat(this string s, int n)
{
    return new String(Enumerable.Range(0, n).SelectMany(x => s).ToArray());
}

public static string Repeat(this char c, int n)
{
    return new String(c, n);
}

39
Bir zamanlar insanlar döngüler kullanırken kullanılır
prabhakaran

2
@prabhakaran Kabul ediyorum ama Linq'in avantajı iletişimde; bir Linq ifadesini zorunlu yapılar kullanarak yeniden uygulamak neredeyse her zaman önemsizdir.
Rodrick Chapman

10
Enumerable.Range(0, n).SelectMany(x => s)basit bir ile değiştirilebilir Enumerable.Repeat(s, n).
Palec

5
@Palec Hayır olamaz. SelectManyHer bir kukla için olacak xbir dizi elde char(yana değerlerin string suygular IEnumerable<char>), ve tüm bu chardiziler bir uzun birleştirilmiş chardizisi. Bunun yerine önerileriniz bir IEnumerable<string>. Aynı değil.
Jeppe Stig Nielsen

2
Yanılmışım, @JeppeStigNielsen. Söylediğin için teşekkürler. Gerçekten kullanmak isteseydim Enumerable.Repeat, birlikte dizeleri bitiştirmek gerekir: string.Concat(Enumerable.Repeat(s, n)). Bu daha önce yayınlanmıştı .
Palec

40

Uzantı yöntemini kullanmaya ne dersiniz?


public static class StringExtensions
{
   public static string Repeat(this char chatToRepeat, int repeat) {

       return new string(chatToRepeat,repeat);
   }
   public  static string Repeat(this string stringToRepeat,int repeat)
   {
       var builder = new StringBuilder(repeat*stringToRepeat.Length);
       for (int i = 0; i < repeat; i++) {
           builder.Append(stringToRepeat);
       }
       return builder.ToString();
   }
}

Daha sonra şunu yazabilirsiniz:

Debug.WriteLine('-'.Repeat(100)); // For Chars  
Debug.WriteLine("Hello".Repeat(100)); // For Strings

Dizeler yerine basit karakterler için stringbuilder sürümünü kullanmanın bir performans testinin size büyük bir performans penalitesi verdiğine dikkat edin: bilgisayarımda ölçülen performans farkı 1:20 arasında: Debug.WriteLine ('-'. Tekrar (1000000)) // char sürümü ve
Debug.WriteLine ("-". Tekrarlama (1000000)) // string sürümü


2
Dize versiyonunun performansı, Binoj Anthony'nin cevapladığıStringBuilder.Insert(Int32, String, Int32) gibi kullanılarak geliştirilebilir .
Palec

23

Buna ne dersin:

//Repeats a character specified number of times
public static string Repeat(char character,int numberOfIterations)
{
    return "".PadLeft(numberOfIterations, character);
}

//Call the Repeat method
Console.WriteLine(Repeat('\t',40));

4
haha .. bir kez bu duruma düştüğümde aklıma gelen şey buydu. Ama şahsen new string('\t', 10)en iyi çözüm buldum
shashwat

Bu hile Essential C # 6.0'da da kullanılır .
Para Odaklı Programcı

22

Bu sorunun zaten beş yaşında olduğunu biliyorum, ancak .Net 2.0'da bile çalışan bir dizeyi tekrarlamanın basit bir yolu var.

Bir dizeyi tekrarlamak için:

string repeated = new String('+', 3).Replace("+", "Hello, ");

İadeler

"Merhaba Merhaba Merhaba, "

Bir dizeyi dizi olarak tekrarlamak için:

// Two line version.
string repeated = new String('+', 3).Replace("+", "Hello,");
string[] repeatedArray = repeated.Split(',');

// One line version.
string[] repeatedArray = new String('+', 3).Replace("+", "Hello,").Split(',');

İadeler

{"Merhaba Merhaba Merhaba", ""}

Basit tutun.



17

İlk örneğiniz Enumerable.Repeat:

private string Tabs(uint numTabs)
{
    IEnumerable<string> tabs = Enumerable.Repeat(
                                 "\t", (int) numTabs);
    return (numTabs > 0) ? 
            tabs.Aggregate((sum, next) => sum + next) : ""; 
} 

aşağıdakilerle daha sıkı bir şekilde yeniden yazılabilir String.Concat:

private string Tabs(uint numTabs)
{       
    return String.Concat(Enumerable.Repeat("\t", (int) numTabs));
}

14

Kullanmak String.Concatve kullanmaktan Enumerable.Repeatdaha ucuz olacakString.Join

public static Repeat(this String pattern, int count)
{
    return String.Concat(Enumerable.Repeat(pattern, count));
}

9
var str = new string(Enumerable.Repeat('\t', numTabs).ToArray());

4

Cevap gerçekten istediğiniz karmaşıklığa bağlıdır. Örneğin, tüm girintilerimi dikey bir çubukla özetlemek istiyorum, bu nedenle girinti dizem aşağıdaki gibi belirlenir:

return new string(Enumerable.Range(0, indentSize*indent).Select(
  n => n%4 == 0 ? '|' : ' ').ToArray());

3

Ve yine başka bir yöntem

new System.Text.StringBuilder().Append('\t', 100).ToString()

Ortaya çıkan dize uzunluğunun StringBuilderyapıcıya aktarılması yeniden tahsis edilmesini sağlar. Yine de, bu, stringkabul edilen cevapta gösterildiği gibi, belirli bir karakteri tekrarlayabilen yapıcıyı kullanmaktan daha konuşkan ve daha az verimlidir .
Palec

3

Benim için sorun yok:

public static class Utils
{
    public static string LeftZerosFormatter(int zeros, int val)
    {
        string valstr = val.ToString();

        valstr = new string('0', zeros) + valstr;

        return valstr.Substring(valstr.Length - zeros, zeros);
    }
}

2

Bir uzantı yöntemi oluşturabilirsiniz

static class MyExtensions
{
    internal static string Repeat(this char c, int n)
    {
        return new string(c, n);
    }
}

O zaman böyle kullanabilirsiniz

Console.WriteLine('\t'.Repeat(10));

1

Şüphesiz kabul edilen cevap, tek bir karakteri tekrar etmenin en iyi ve en hızlı yoludur.

Binoj Anthony'nin cevabı, bir ipi tekrarlamanın basit ve oldukça etkili bir yoludur.

Ancak, biraz daha kod sakıncası yoksa, bu dizeleri daha da hızlı bir şekilde oluşturmak için dizi doldurma tekniğimi kullanabilirsiniz. Karşılaştırma testlerimde, aşağıdaki kod StringBuilder.Insert kodunun yaklaşık% 35'inde yürütüldü.

public static string Repeat(this string value, int count)
{
    var values = new char[count * value.Length];
    values.Fill(value.ToCharArray());
    return new string(values);
}

public static void Fill<T>(this T[] destinationArray, params T[] value)
{
    if (destinationArray == null)
    {
        throw new ArgumentNullException("destinationArray");
    }

    if (value.Length > destinationArray.Length)
    {
        throw new ArgumentException("Length of value array must not be more than length of destination");
    }

    // set the initial array value
    Array.Copy(value, destinationArray, value.Length);

    int copyLength, nextCopyLength;

    for (copyLength = value.Length; (nextCopyLength = copyLength << 1) < destinationArray.Length; copyLength = nextCopyLength)
    {
        Array.Copy(destinationArray, 0, destinationArray, copyLength, copyLength);
    }

    Array.Copy(destinationArray, 0, destinationArray, copyLength, destinationArray.Length - copyLength);
}

Bu dizi doldurma tekniği hakkında daha fazla bilgi için bkz. Bir diziyi tek bir değerle doldurmanın en hızlı yolu


0

Bunu dene:

  1. Microsoft.VisualBasic başvurusu ekle
  2. Kullan: Dize sonucu = Microsoft.VisualBasic.Strings.StrDup (5, "hi");
  3. İşinize yarayıp yaramadığını bana bildirin.

Başka bir montaja bağımlılık ve onu yükleme ihtiyacı çoğu durumda böyle bir işleve ihtiyaç duyduğunuzda mantıksızdır. Yine de, .NET'te böyle bir şey olduğunu bilmek güzel.
Palec

Farklı bağlamlarda birçok artı ve eksileri vardır, bu yüzden herkes bulunduğu duruma bağlı olarak karar vermelidir.
Toso Pankovski

-1

Önceki bir öneriye çok benzemekle birlikte, basit tutmayı ve aşağıdakileri uygulamayı seviyorum:

string MyFancyString = "*";
int strLength = 50;
System.Console.WriteLine(MyFancyString.PadRight(strLength, "*");

Standart .Net gerçekten,


Sadece dolgu ekleyecek, tekrar etmiyor
levi
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.