web-dev-qa-db-ja.com

IEnumerable <char>から文字列

これに出くわしたことは一度もありませんが、IEnumerable<char>stringに変換する本当に簡単な方法を見つけられないことに驚いています。

考えられる最良の方法はstring str = new string(myEnumerable.ToArray());ですが、私には、これは新しいchar[]を作成し、それから新しいstringを作成するようです。

これは、どこかで.NETフレームワークに組み込まれている一般的な機能だと思います。これを行う簡単な方法はありますか?

興味がある人のために、これを使用したい理由は、LINQを使用して文字列をフィルター処理するためです。

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

String.Concat() を使用できます。

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

Caveat:このアプローチには、パフォーマンスへの影響があります。 String.Concatは特殊な文字のコレクションではないため、すべての文字が文字列に変換され、前述のように連結されているように動作します ドキュメントで- そして実際に)。確かにこれはあなたにこのタスクを達成するための組み込みの方法を提供しますが、それはもっと良くできます。

フレームワーク内にcharという特殊なケースを実装するものはないと思うので、実装する必要があります。文字列ビルダーに文字を追加する単純なループは、作成するのに十分簡単です。


ここに、私が開発マシンで取ったいくつかのベンチマークがありますが、それは適切に見えます。

32ビットリリースビルドの300文字シーケンスで1000000回の反復:

 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のリリース用に編集

.Net Core 2.1のリリースのためにテストを繰り返すと、次のような結果が得られます

「Concat」の1000000回の反復には842ミリ秒かかりました。

「新しい文字列」の1000000回の反復には1009msかかりました。

「sb」の1000000回の反復には902msかかりました。

つまり、.Net Core 2.1以降を使用している場合、Concatが重要です。

詳細については、 MSブログ投稿 を参照してください。


これを 別の質問 の主題にしましたが、ますます多くのことが、この質問に対する直接的な回答になりつつあります。

IEnumerable<char>stringに変換する3つの簡単なメソッドのパフォーマンステストをいくつか実行しました。これらのメソッドは

新しい文字列

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

私のテストでは、 リンクされた質問 で詳細に説明されています。1000000の繰り返し"Some reasonably small test data"の結果は次のようになります。

「Concat」の1000000回の反復には1597msかかりました。

「新しい文字列」の1000000回の反復には869ミリ秒かかりました。

「StringBuilder」の1000000回の反復には748msかかりました。

これは、このタスクにstring.Concatを使用する正当な理由がないことを示唆しています。シンプルにしたい場合はnew stringアプローチを使用し、パフォーマンスが必要な場合はStringBuilder

私は主張を警告しますが、実際にはこれらの方法はすべてうまく機能し、これはすべて最適化を超えている可能性があります。

76
Jodrell

.NET 4以降、多くの文字列メソッドは引数としてIEnumerableを取ります。

string.Concat(myEnumerable);
19
MikeP

私のデータは、Jodrellが投稿した結果に反しています。最初に、私が使用している拡張メソッドを見てください。

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

私の結果

あり

  • STRLEN = 31
  • ITERATIONS = 1000000

入力

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

結果

  • 連結:1x
  • 新規:3x
  • StringBuilder:3x

入力

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

結果

  • 連結:1x
  • 新規:7x
  • StringBuilder:7x

入力

  • ((IEnumerable<char>)RandomString(STRLEN))(これは単なるアップキャストです)

結果

  • 連結:0ミリ秒
  • 新規:2000ミリ秒
  • StringBuilder:2000ミリ秒
  • ダウンキャスト:0 ms

これは、.NET Framework 3.5をターゲットとするIntel i5 760で実行しました。

10
hBGl

別の可能性は

string.Join("", myEnumerable);

パフォーマンスを測定しませんでした。

10
nitrogenycs

StringBuilderの回答のより簡潔なバージョンを次に示します。

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

Jeff Mercadoが使用したのと同じテストを使用してこれを計りました。これは、同じ300文字シーケンス(32ビットリリースビルド)での1,000,000回の反復で、明示的なテストよりも1秒遅くなりました。

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

あなたがアキュムレータのファンなら、ここに行きます。

9
Adam Smith