C # veya Java: StringBuilder ile dizeleri başa ekleyin?


104

Kullanarak dizeleri ekleyebileceğimizi biliyorum StringBuilder. Sunulan StringBuilderperformans avantajlarını koruyabilmemiz için dizeleri başa ekleyebileceğimiz (yani bir dizenin önüne dizeler ekleyebileceğimiz) bir yol var mı StringBuilder?


Sorunuzu anlamıyorum
Maurice Perry

5
Başa ekleyin. Kelime başa eklenmiştir. Bir dizeyi önceden eklemek, bir dizenin her iki ucuna aynı anda eklemek gibi bir şey olmalı, sanırım?
Joel Mueller

Yanıtlar:



29

Bir Dize'nin başına eklenmesi genellikle ekleme noktasından sonra her şeyin arka dizideki bazılarını geri kopyalamasını gerektirir, bu nedenle sona eklemek kadar hızlı olmayacaktır.

Ancak bunu Java'da şu şekilde yapabilirsiniz (C #'da aynıdır, ancak yöntem denir Insert):

aStringBuilder.insert(0, "newText");

11

Çok sayıda ön ekleme ile yüksek performansa ihtiyacınız varsa, kendi sürümünüzü yazmanız StringBuilder(veya başka birinin sürümünü kullanmanız) gerekir. Standart ile StringBuilder(teknik olarak farklı şekilde uygulanabilmesine rağmen) ekleme, ekleme noktasından sonra verilerin kopyalanmasını gerektirir. N parça metin eklemek O (n ^ 2) süre alabilir.

Saf bir yaklaşım char[], uzunluğun yanı sıra destek tamponuna bir ofset eklemek olacaktır . Bir başa ekleme için yeterli yer olmadığında, verileri kesinlikle gerekenden daha fazla taşıyın. Bu, performansı O (n log n) 'ye düşürür (sanırım). Daha rafine bir yaklaşım, tamponu döngüsel yapmaktır. Bu şekilde dizinin her iki ucundaki boş alan bitişik hale gelir.


5

Bir uzatma yöntemi deneyebilirsiniz:

/// <summary>
/// kind of a dopey little one-off for StringBuffer, but 
/// an example where you can get crazy with extension methods
/// </summary>
public static void Prepend(this StringBuilder sb, string s)
{
    sb.Insert(0, s);
}

StringBuilder sb = new StringBuilder("World!");
sb.Prepend("Hello "); // Hello World!

5

Dizeyi tersten oluşturabilir ve ardından sonucu tersine çevirebilirsiniz. O (n ^ 2) en kötü durum maliyeti yerine O (n) maliyetine maruz kalırsınız.


2
Bu sadece tek tek karakterler ekliyorsanız işe yarar. Aksi takdirde, eklediğiniz her dizeyi tersine çevirmeniz gerekir; bu, dizelerin boyutuna ve sayısına bağlı olarak tüm tasarrufları olmasa da en çok tüketir.
Kızak

4

Kullanmadım ama Java için Halatlar ilgi çekici geliyor. Proje adı kelimeler üzerinde bir oyundur, ciddi işler için String yerine bir Halat kullanın . Ön harcama ve diğer işlemler için performans cezasını ortadan kaldırır. Bunu çok yapacaksanız, bir göz atmaya değer.

Bir halat, Teller için yüksek performanslı bir alternatiftir. "Halatlar: Dizelere Bir Alternatif" bölümünde ayrıntılı olarak açıklanan veri yapısı, başa ekleme, ekleme, silme ve ekleme gibi yaygın dizgi modifikasyonları için hem String hem de StringBuffer'dan asimptotik olarak daha iyi performans sağlar. Dizeler gibi, ipler de değişmezdir ve bu nedenle çok iş parçacıklı programlamada kullanım için çok uygundur.


4

Java'nın StringBuilder sınıfını kullanarak başa eklemek istiyorsanız şunları yapabilirsiniz:

StringBuilder str = new StringBuilder();
str.Insert(0, "text");


2

Ekle () kullanmayı deneyin

StringBuilder MyStringBuilder = new StringBuilder("World!");
MyStringBuilder.Insert(0,"Hello "); // Hello World!

2

Diğer yorumlara bakılırsa, bunu yapmanın standart bir hızlı yolu yoktur. StringBuilder'ın Kullanımı.Insert(0, "text") , acı verici derecede yavaş String birleştirme kullanmaktan yaklaşık 1-3 kat daha hızlıdır (> 10000 bitiştirmeye dayalı olarak), bu nedenle aşağıda potansiyel olarak binlerce kez daha hızlı bir şekilde başa dönecek bir sınıf bulunmaktadır!

Ben gibi diğer bazı temel işlevleri yer verdik append(), subString()ve length()vb Hem ekler ve prepends yavaş StringBuilder ekler daha 3x yaklaşık iki kat daha hızlı değişir. StringBuilder gibi, bu sınıftaki arabellek, metin eski arabellek boyutunu aştığında otomatik olarak artacaktır.

Kod epeyce test edildi, ancak hatasız olduğunu garanti edemem.

class Prepender
{
    private char[] c;
    private int growMultiplier;
    public int bufferSize;      // Make public for bug testing
    public int left;            // Make public for bug testing
    public int right;           // Make public for bug testing
    public Prepender(int initialBuffer = 1000, int growMultiplier = 10)
    {
        c = new char[initialBuffer];
        //for (int n = 0; n < initialBuffer; n++) cc[n] = '.';  // For debugging purposes (used fixed width font for testing)
        left = initialBuffer / 2;
        right = initialBuffer / 2;
        bufferSize = initialBuffer;
        this.growMultiplier = growMultiplier;
    }
    public void clear()
    {
        left = bufferSize / 2;
        right = bufferSize / 2;
    }
    public int length()
    {
        return right - left;
    }

    private void increaseBuffer()
    {
        int nudge = -bufferSize / 2;
        bufferSize *= growMultiplier;
        nudge += bufferSize / 2;
        char[] tmp = new char[bufferSize];
        for (int n = left; n < right; n++) tmp[n + nudge] = c[n];
        left += nudge;
        right += nudge;
        c = new char[bufferSize];
        //for (int n = 0; n < buffer; n++) cc[n]='.';   // For debugging purposes (used fixed width font for testing)
        for (int n = left; n < right; n++) c[n] = tmp[n];
    }

    public void append(string s)
    {
        // If necessary, increase buffer size by growMultiplier
        while (right + s.Length > bufferSize) increaseBuffer();

        // Append user input to buffer
        int len = s.Length;
        for (int n = 0; n < len; n++)
        {
            c[right] = s[n];
            right++;
        }
    }
    public void prepend(string s)
    {
        // If necessary, increase buffer size by growMultiplier
        while (left - s.Length < 0) increaseBuffer();               

        // Prepend user input to buffer
        int len = s.Length - 1;
        for (int n = len; n > -1; n--)
        {
            left--;
            c[left] = s[n];
        }
    }
    public void truncate(int start, int finish)
    {
        if (start < 0) throw new Exception("Truncation error: Start < 0");
        if (left + finish > right) throw new Exception("Truncation error: Finish > string length");
        if (finish < start) throw new Exception("Truncation error: Finish < start");

        //MessageBox.Show(left + " " + right);

        right = left + finish;
        left = left + start;
    }
    public string subString(int start, int finish)
    {
        if (start < 0) throw new Exception("Substring error: Start < 0");
        if (left + finish > right) throw new Exception("Substring error: Finish > string length");
        if (finish < start) throw new Exception("Substring error: Finish < start");
        return toString(start,finish);
    }

    public override string ToString()
    {
        return new string(c, left, right - left);
        //return new string(cc, 0, buffer);     // For debugging purposes (used fixed width font for testing)
    }
    private string toString(int start, int finish)
    {
        return new string(c, left+start, finish-start );
        //return new string(cc, 0, buffer);     // For debugging purposes (used fixed width font for testing)
    }
}

1

StringBuilder için basit bir sınıfla kendiniz bir uzantı oluşturabilirsiniz:

namespace Application.Code.Helpers
{
    public static class StringBuilderExtensions
    {
        #region Methods

        public static void Prepend(this StringBuilder sb, string value)
        {
            sb.Insert(0, value);
        }

        public static void PrependLine(this StringBuilder sb, string value)
        {
            sb.Insert(0, value + Environment.NewLine);
        }

        #endregion
    }
}

Ardından şunu ekleyin:

using Application.Code.Helpers;

StringBuilder'ı kullanmak istediğiniz herhangi bir sınıfın tepesinde ve bir StringBuilder değişkeniyle intelli-sense'i her kullandığınızda, Prepend ve PrependLine yöntemleri görünecektir. Başa Eklemeyi kullandığınızda, Eklemekte olduğunuza göre ters sırada Başa Eklemeniz gerekeceğini unutmayın.


0

Bu çalışmalı:

aStringBuilder = "newText" + aStringBuilder; 

.NET'te bu, tür değerleriyle mükemmel çalışır string, ancak tür değerleriyle çalışmaz StringBuilder. @ScubaSteve'nin cevabı iyi çalışıyor.
Contango
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.