web-gelistirme-sc.com

IEnumerable <char> dize

Daha önce hiç bununla karşılaşmamıştım, ama şimdi bir IEnumerable<char> - string dönüştürmek için kolay bir yol bulamadığım için şaşırdım.

Düşünebilmemin en iyi yolu string str = new string(myEnumerable.ToArray());'dır, fakat bana göre, bunun yeni bir char[] yaratacağı ve daha sonra pahalı görünen yeni bir string yaratacağı görülüyor.

Bunun, .NET Framework içerisinde bir yerde yerleşik olarak kullanılan ortak işlev olduğunu düşünmüştüm. Bunu yapmanın daha basit bir yolu var mı?

İlgilenenler için, bunu kullanmak istememin nedeni dizeleri filtrelemek için LINQ kullanmak:

string allowedString = new string(inputString.Where(c => allowedChars.Contains(c)).ToArray());
131
Connell

String.Concat() kullanabilirsiniz.

var allowedString = String.Concat(
    inputString.Where(c => allowedChars.Contains(c))
);

Uyarısı : Bu yaklaşımın bazı performans etkileri olacaktır. String.Concat özel durum koleksiyonları içermez, bu yüzden her karakter bir dizgeye dönüştürülmüş ve daha sonra belirtildiği şekilde birleştirilmiştir belgelerde ( - ve aslında yapar). Elbette, bu görevi başarmanız için size yerleşik bir yol sunar, ancak daha iyi yapılabilir.

Özel durum char olacak çerçeve içinde herhangi bir uygulama olduğunu sanmıyorum, bu yüzden bunu uygulamanız gerekecek. Bir karakter oluşturucusuna karakter ekleyen basit bir döngü oluşturmak için yeterince basittir.


İşte bir dev makinede aldığım bazı kriterler ve doğru görünüyor.

32 bitlik sürüm oluşturma işleminde 300 karakterlik bir dizide 1000000 yineleme:

 ToArrayString: 00: 00: 03.1695463 
 Concat: 00: 00: 07.2518054 
 StringBuilderChars: 00: 00: 03.1335455 
 StringBuilderStrings: 00: 00: 06.4618266 
static readonly IEnumerable<char> seq = Enumerable.Repeat('a', 300);

static string ToArrayString(IEnumerable<char> charSequence)
{
    return new String(charSequence.ToArray());
}

static string Concat(IEnumerable<char> charSequence)
{
    return String.Concat(charSequence);
}

static string StringBuilderChars(IEnumerable<char> charSequence)
{
    var sb = new StringBuilder();
    foreach (var c in charSequence)
    {
        sb.Append(c);
    }
    return sb.ToString();
}

static string StringBuilderStrings(IEnumerable<char> charSequence)
{
    var sb = new StringBuilder();
    foreach (var c in charSequence)
    {
        sb.Append(c.ToString());
    }
    return sb.ToString();
}
136
Jeff Mercado

.Net Core 2.1 sürümü için düzenlenmiştir.

Net Çekirdek 2.1 sürümü için testi tekrarlayarak, böyle sonuçlar alıyorum

1000000 yineleme "Concat" 842ms aldı.

1000000 "new String" yinelemesi 1009ms aldı.

1000000 yineleme "sb" 902ms aldı.

Kısacası, .Net Core 2.1 veya üstünü kullanıyorsanız, Concat kraldır.

Daha fazla detay için bakınız MS blog yazısı .


Bu konuyu başka bir sor yaptım, ama gittikçe daha fazla, bu soruya doğrudan bir cevap haline geliyor.

Bir IEnumerable<char> bir string dönüştürmek için 3 basit yöntem bazı performans testleri yaptım, bu yöntemler

yeni dize

return new string(charSequence.ToArray());

Concat

return string.Concat(charSequence)

StringBuilder

var sb = new StringBuilder();
foreach (var c in charSequence)
{
    sb.Append(c);
}

return sb.ToString();

Testlerimde, bu bağlantılı sor 'da, 1000000 iterasyonlarında "Some reasonably small test data" yinelemelerinde ayrıntılı olarak verilmiştir.

1000000 "Concat" yinelemesi 1597ms aldı.

1000000 yineleme "yeni dize" 869ms aldı.

1000000 "StringBuilder" yinelemesi 748ms aldı.

Bu bana bu görev için string.Concat kullanmak için iyi bir neden olmadığını gösteriyor. Basitlik istiyorsanız, yeni dize yaklaşımını kullanın ve performans istiyorsanız StringBuilder .

Ben iddiamı boşa harcardım, pratikte tüm bu yöntemler iyi çalışıyor ve bu da tüm bunların optimizasyonun üzerinde olabilirdi.

76
Jodrell

.NET 4'ten itibaren birçok string yöntemi IE değişkenini argüman olarak alır.

string.Concat(myEnumerable);
19
MikeP

Verilerim Jodrell'in yayınladığı sonuçlara aykırı. İlk önce kullandığım uzatma yöntemlerine bir göz atın:

public static string AsStringConcat(this IEnumerable<char> characters)
{        
    return String.Concat(characters);
}

public static string AsStringNew(this IEnumerable<char> characters)
{
    return new String(characters.ToArray());
}

public static string AsStringSb(this IEnumerable<char> characters)
{
    StringBuilder sb = new StringBuilder();
    foreach (char c in characters)
    {
        sb.Append(c);
    }
    return sb.ToString();
}

Benim sonuçlarım

With

  • STRLEN = 31
  • İTERASYONLAR = 1000000

giriş

  • ((IEnumerable<char>)RandomString(STRLEN)).Reverse()

Sonuçlar

  • Concat: 1x
  • Yeni: 3x
  • StringBuilder: 3x

giriş

  • ((IEnumerable<char>)RandomString(STRLEN)).Take((int)ITERATIONS/2)

Sonuçlar

  • Concat: 1x
  • Yeni: 7x
  • StringBuilder: 7x

giriş

  • ((IEnumerable<char>)RandomString(STRLEN))(bu sadece bir upcast)

Sonuçlar

  • Concat: 0 ms
  • Yeni: 2000 ms
  • StringBuilder: 2000 ms
  • Downcast: 0 ms

Bunu .NET Framework 3.5'i hedefleyen bir Intel i5 760'ta kullandım.

10
hBGl

Başka bir olasılık kullanıyor

string.Join("", myEnumerable);

Performansı ölçmedim.

10
nitrogenycs

İşte StringBuilder cevabının daha kısa ve özlü bir versiyonu:

return charSequence.Aggregate(new StringBuilder(), (seed, c) => seed.Append(c)).ToString();

Bunu, Jeff Mercado'nun kullandığı aynı testleri kullanarak zamanlamıştım ve bu aynı 300 karakter dizisindeki (32-bit sürüm oluşturma) 1.000.000 yineleme boyunca 1 saniye daha açıktı:

static string StringBuilderChars(IEnumerable<char> charSequence)
{
    var sb = new StringBuilder();
    foreach (var c in charSequence)
    {
        sb.Append(c);
    }
    return sb.ToString();
}

Yani eğer bir akümülatör hayranı iseniz o zaman işte buradasınız.

9
Adam Smith