これに出くわしたことは一度もありませんが、IEnumerable<char>
をstring
に変換する本当に簡単な方法を見つけられないことに驚いています。
考えられる最良の方法はstring str = new string(myEnumerable.ToArray());
ですが、私には、これは新しいchar[]
を作成し、それから新しいstring
を作成するようです。
これは、どこかで.NETフレームワークに組み込まれている一般的な機能だと思います。これを行う簡単な方法はありますか?
興味がある人のために、これを使用したい理由は、LINQを使用して文字列をフィルター処理するためです。
string allowedString = new string(inputString.Where(c => allowedChars.Contains(c)).ToArray());
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();
}
。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。
私は主張を警告しますが、実際にはこれらの方法はすべてうまく機能し、これはすべて最適化を超えている可能性があります。
.NET 4以降、多くの文字列メソッドは引数としてIEnumerableを取ります。
string.Concat(myEnumerable);
私のデータは、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();
}
あり
入力
((IEnumerable<char>)RandomString(STRLEN)).Reverse()
結果
入力
((IEnumerable<char>)RandomString(STRLEN)).Take((int)ITERATIONS/2)
結果
入力
((IEnumerable<char>)RandomString(STRLEN))
(これは単なるアップキャストです)結果
これは、.NET Framework 3.5をターゲットとするIntel i5 760で実行しました。
別の可能性は
string.Join("", myEnumerable);
パフォーマンスを測定しませんでした。
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();
}
あなたがアキュムレータのファンなら、ここに行きます。