Najlepszy sposób na powtórzenie znaku w C #


812

Jaki jest najlepszy sposób na wygenerowanie ciągu \tw C #

Uczę się języka C # i eksperymentuję z różnymi sposobami mówienia tego samego.

Tabs(uint t)Jest to funkcja, która zwraca stringz tilością \t„S

Na przykład Tabs(3)zwraca"\t\t\t"

Który z tych trzech sposobów wdrożenia Tabs(uint numTabs)jest najlepszy?

Oczywiście zależy to od tego, co oznacza „najlepszy”.

  1. Wersja LINQ to tylko dwie linie, co jest miłe. Ale czy wezwania do powtarzania i agregowania niepotrzebnie pochłaniają czas / zasoby?

  2. StringBuilderWersja jest bardzo jasne, ale to StringBuilderklasa jakoś wolniej?

  3. stringWersja podstawowa, co oznacza, że jest łatwe do zrozumienia.

  4. Czy to w ogóle nie ma znaczenia? Czy wszystkie są równe?

To są wszystkie pytania, które pomogą mi lepiej poznać C #.

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

Odpowiedzi:


1490

A co z tym:

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

Gdzie njest liczba powtórzeń ciągu znaków.

Albo lepiej:

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

2
czy jest jakiś sposób, aby powtórzyć to dla słowa? zamiast używać „\ t” jak używać „czas”
asdfkjasdfjk

6
@ user1478137 Lub, lepiej (również w dół): to
Xynariz

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

Zwroty

„abab”

I

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

Zwroty

„aa”

od...

Czy jest wbudowana funkcja powtarzania łańcucha lub znaku w .net?


1
Ulepsz to, robiąc to bez Linq i z StruingBuilder!
Bitterblue,

4
„StringBuilder” niekoniecznie jest szybszy stackoverflow.com/questions/585860/…
Schiavini,

6
Może nie być szybszy, ale może zaoszczędzić na przydziałach pamięci (ciśnieniu), jeśli określisz z góry prawidłową pojemność, i może to być tak samo ważne, jak mikroprocesor profilowania tego.
wekempf

1
var strRepeat = string.Concat (Enumerable.Repeat („ABC”, 1000000)); // 50ms
yongfa365,

1
@Pharap string.Joinbył szybszy w tym przykładzie, ponieważ używali separatora spacji. string.Concatjest odpowiedni, gdy nie ma ogranicznika.
Carter Medlin,

124

We wszystkich wersjach .NET możesz powtórzyć ciąg w ten sposób:

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

Powtarzanie postaci new String('\t', count)jest najlepszym wyborem. Zobacz odpowiedź @CMS .


7
Jest to zdecydowanie najszybszy pod względem wydajności ciąg. Inne metody generują zbyt wiele narzutów.
środek przestrzeni

@midspace Czy wiesz, czy ktoś wyjaśnił, dlaczego inne odpowiedzi są gorsze? Zakładałbym, że natywny String.Concat będzie tak samo zoptymalizowany wewnętrznie jak StringBuilder
Marie

@Marie Poniższy artykuł wyjaśnia niektóre zalety. support.microsoft.com/en-au/help/306822/… W przeciwnym razie dwa inne czynniki to: StringBuilder dopuszcza ciągi znaków i nie ogranicza się tylko do znaku (choć nie dotyczy to pierwotnego pytania) oraz ciągu znaków. Concat odpowiedź powyżej musi najpierw utworzyć tablicę za pomocą Enumerable.Repeat. Jak powiedziałem, jest to niepotrzebny narzut.
midspace

Zakładałem, że najpierw nie utworzy tablicy, ponieważ może po prostu iterować element po elemencie. Dziękuję za link, dam ci przeczytać!
Marie

63

Najlepszą wersją jest z pewnością użycie wbudowanego sposobu:

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

Spośród innych rozwiązań preferuj najłatwiejsze; tylko jeśli okaże się to zbyt wolne, staraj się znaleźć bardziej wydajne rozwiązanie.

Jeśli użyjesz StringBuilderi znasz z góry jego wynikową długość, użyj również odpowiedniego konstruktora, jest to o wiele bardziej wydajne, ponieważ oznacza, że ​​ma miejsce tylko jeden czasochłonny przydział i nie ma potrzeby niepotrzebnego kopiowania danych. Bzdury: oczywiście powyższy kod jest bardziej wydajny.


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

7
Moje testy porównawcze są new string('\t', len)od 2x do 7x szybsze niż StringBuilderpodejście. Jak myślisz, dlaczego StringBuilderw tym przypadku jest bardziej wydajny?
StriplingWarrior

6
@StriplingWarrior Dzięki za naprawienie tego (po tym, jak stoi tu od dwóch lat, nie mniej!).
Konrad Rudolph

51

Metody rozszerzenia:

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
Dawno, dawno temu ludzie używali pętli while
prabhakaran

2
@prabhakaran Zgadzam się, ale zaletą Linq jest komunikacja; prawie zawsze trywialne jest zaimplementowanie wyrażenia Linq przy użyciu konstrukcji imperatywnych.
Rodrick Chapman

10
Enumerable.Range(0, n).SelectMany(x => s)można zastąpić prostym Enumerable.Repeat(s, n).
Palec

5
@Palec Nie, nie można. SelectManyBędzie dla każdego pojedynczego manekina xotrzymując sekwencji charwartości (od string snarzędzi IEnumerable<char>), a wszystkie te charsekwencje są łączone z jednej długiej charsekwencji. To, co sugerujesz, da IEnumerable<string>. To nie jest to samo.
Jeppe Stig Nielsen,

2
Myliłem się, @JeppeStigNielsen. Dzięki za zgłoszenie się. Gdybym naprawdę chciał użyć Enumerable.Repeat, musiałbym łączyć ciągi razem: string.Concat(Enumerable.Repeat(s, n)). To już zostało opublikowane .
Palec

40

Co z użyciem metody rozszerzenia?


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

Możesz wtedy napisać:

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

Zauważ, że test wydajności użycia wersji programu budującego ciąg dla prostych znaków zamiast ciągów daje dużą karę za wydajność: na moim komputerze różnica mierzonej wydajności wynosi 1:20 pomiędzy: Debug.WriteLine ('-'. Powtórz (1000000)) // wersja char i
Debug.WriteLine („-”. Powtórz (1000000)) // wersja string


2
Wydajność wersji łańcuchowej można poprawić, używając StringBuilder.Insert(Int32, String, Int32), jak odpowiedział Binoj Anthony .
Palec,

23

Co powiesz na to:

//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 ... o tym mogłem pomyśleć, kiedy raz wpadłem w tę sytuację. Ale osobiście uważam, że new string('\t', 10)to najlepsze rozwiązanie
shashwat

Ta sztuczka jest również używana w Essential C # 6.0 .
Programista zorientowany na pieniądze

22

Wiem, że to pytanie ma już pięć lat, ale istnieje prosty sposób na powtórzenie ciągu znaków, który działa nawet w .Net 2.0.

Aby powtórzyć ciąg:

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

Zwroty

"Witam Witam Witam, "

Aby powtórzyć ciąg jako tablicę:

// 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(',');

Zwroty

{"Witam Witam Witam", ""}

Nie komplikuj.



17

Twój pierwszy przykład, który wykorzystuje Enumerable.Repeat:

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

można napisać bardziej kompaktowo za pomocą String.Concat:

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

14

Korzystanie String.Concati Enumerable.Repeatktóre będzie tańsze niż korzystanieString.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

Odpowiedź naprawdę zależy od wymaganej złożoności. Na przykład chcę obrysować wszystkie moje wcięcia pionowym paskiem, więc mój ciąg wcięcia jest określany w następujący sposób:

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

3

I jeszcze jedna metoda

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

Przekazanie wynikowej długości łańcucha StringBuilderkonstruktorowi oszczędza realokacji. Jest to jednak bardziej gadatliwe i mniej wydajne niż użycie stringkonstruktora, który może powtórzyć dany znak, jak już pokazano w zaakceptowanej odpowiedzi.
Palec

3

Dla mnie jest w porządku:

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

Możesz utworzyć metodę rozszerzenia

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

Następnie możesz użyć tego w ten sposób

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

1

Bez wątpienia przyjęta odpowiedź jest najlepszym i najszybszym sposobem na powtórzenie jednego znaku.

Odpowiedź Binoj Anthony'ego to prosty i dość skuteczny sposób na powtórzenie łańcucha.

Jeśli jednak nie przeszkadza ci trochę więcej kodu, możesz użyć mojej techniki wypełniania tablic, aby efektywnie tworzyć te ciągi jeszcze szybciej. W moich testach porównawczych poniższy kod został wykonany w około 35% czasu kodu StringBuilder.Insert.

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

Aby uzyskać więcej informacji na temat tej techniki wypełniania tablicy, zobacz Najszybszy sposób wypełnienia tablicy jedną wartością


0

Spróbuj tego:

  1. Dodaj odwołanie Microsoft.VisualBasic
  2. Użyj: Ciąg wynik = Microsoft.VisualBasic.Strings.StrDup (5, „cześć”);
  3. Daj mi znać, czy to działa dla Ciebie.

Dodanie zależności od innego zestawu i konieczność załadowania go jest nieuzasadnione w większości przypadków, gdy potrzebujesz takiej funkcjonalności. Jednak dobrze wiedzieć, że jest coś takiego w .NET.
Palec

Istnieje wiele zalet i wad w różnych kontekstach, więc każdy powinien zdecydować w zależności od sytuacji, w której się znajduje.
Toso Pankovski,

-1

Chociaż bardzo podobna do poprzedniej sugestii, lubię ją upraszczać i stosować następujące zasady:

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

Standardowo .Net naprawdę,


Po prostu doda padding, nie powtarza się
levi
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.