33

StringBuiler は変更可能なオブジェクトです。F# では、可能な限り不変性を採用することをお勧めします。したがって、突然変異ではなく変換を使用する必要があります。F# で文字列を作成する場合、これは StringBuilder に適用されますか? F# の不変の代替手段はありますか? もしそうなら、この代替手段は効率的ですか?

スニペット

4

2 に答える 2

49

StringBuilderF# での使用はまったく問題ないと思い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た。リリース ビルドではより高速になる可能性が高いですが、かなり代表的なものだと思います。

于 2013-09-03T16:03:33.697 に答える