StringBuiler は変更可能なオブジェクトです。F# では、可能な限り不変性を採用することをお勧めします。したがって、突然変異ではなく変換を使用する必要があります。F# で文字列を作成する場合、これは StringBuilder に適用されますか? F# の不変の代替手段はありますか? もしそうなら、この代替手段は効率的ですか?
2 に答える
StringBuilder
F# での使用はまったく問題ないと思いsb.Append
ます。 の現在のインスタンスを返すという事実StringBuilder
は、関数で簡単に使用できることを意味しfold
ます。これは依然として必須ですが (オブジェクトは変更されています)、 への参照を公開しない場合は、機能的なスタイルにうまく適合しますStringBuilder
。
しかし同様に、文字列のリストを作成し、 を使用してそれらを連結することもできますString.concat
- これは を使用するのとほぼ同じくらい効率的StringBuilder
です (遅くなりますが、それほどではありません - を使用して文字列を連結するよりもはるかに高速です+
) 。
したがって、リストは同様のパフォーマンスを提供しますが、それらは不変です (そして同時実行などでうまく機能します) - リストの先頭に文字列を追加するだけでよいため、文字列をアルゴリズム的に構築する場合に適しています - これはリストに対する非常に効率的な操作 (そして文字列を逆にする)。また、リスト式を使用すると、非常に便利な構文が得られます。
// Concatenating strings using + (2.3 seconds)
let s1 = [ for i in 0 .. 25000 -> "Hello " ] |> Seq.reduce (+)
s1.Length
// Creating immutable list and using String.concat (5 ms)
let s2 = [ for i in 0 .. 25000 -> "Hello " ] |> String.concat ""
s2.Length
// Creating a lazy sequence and concatenating using StringBuilder & fold (5 ms)
let s3 =
seq { for i in 0 .. 25000 -> "Hello " }
|> Seq.fold(fun (sb:System.Text.StringBuilder) s ->
sb.Append(s)) (new System.Text.StringBuilder())
|> fun x -> x.ToString()
s3.Length
// Imperative solution using StringBuilder and for loop (1 ms)
let s4 =
( let sb = new System.Text.StringBuilder()
for i in 0 .. 25000 do sb.Append("Hello ") |> ignore
sb.ToString() )
s4.Length
時間は、F# Interactive を使用してかなり高速な作業マシンで測定されまし#time
た。リリース ビルドではより高速になる可能性が高いですが、かなり代表的なものだと思います。