StringBuilerは可変オブジェクトです。F#は、不変性を可能な限り使用することを奨励します。したがって、突然変異ではなく形質転換を使うべきです。 F#で文字列を作成する場合、これはStringBuilderに適用されますか?そこにF#不変の代替はありますか?もしそうなら、この代わりに効率的な方法がありますか?F#でStringBuilderを使用するのは正しいことですか?
答えて
私はF#でStringBuilder
を使用することがあると思います完全に正確 - 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#インタラクティブで#time
を使用して、私の、かなり高速で、作業機械で測定した - それはリリースビルドで速くなることは非常に可能性があり、私は彼らがかなり代表的だと思う。
s2は 'String.concat'の前に' List.rev'を入れていますか?あなたが上記のように、リストはおそらくそれらが連結したいと思う方法の逆順になるように構築されるでしょう。 – mydogisbox
あなたは、高性能刺さ連結の必要性を持っている場合は、その文字列ビルダは、おそらく行くための正しい方法である、しかし、文字列ビルダをより機能的にする方法があります。一般に、機能的なプログラムで変更可能性が必要な場合、これを実行する適切な方法は、機能的なラッパーを作成することです。 F#では、これは通常、計算式として表されます。文字列ビルダ計算式hereの例があります。
使用例:
//Create a function which builds a string from an list of bytes
let bytes2hex (bytes : byte []) =
string {
for byte in bytes -> sprintf "%02x" byte
} |> build
//builds a string from four strings
string {
yield "one"
yield "two"
yield "three"
yield "four"
} |> build
編集: 私は上記の計算式の新しい実装を作った後、トーマス4つのソリューションのリリースバージョンに加えて、私の計算式と、私は以前にリンクされ、計算式を実行しました。
s1 elapsed Time: 128150 ms //concatenation
s2 elapsed Time: 459 ms //immutable list + String.concat
s3 elapsed Time: 354 ms //lazy sequence and concatenating using StringBuilder & fold
s4 elapsed Time: 39 ms //imperative
s5 elapsed Time: 235 ms //my computation expression
s6 elapsed Time: 334 ms //the linked computation expression
s3は必須の9倍、s5は6倍の時間がかかります。
open System.Text
type StringBuilderUnion =
| Builder of StringBuilder
| StringItem of string
let build = function | Builder(x) -> string x | StringItem(x) -> string x
type StringBuilderCE() =
member __.Yield (txt : string) = StringItem(txt)
member __.Yield (c : char) = StringItem(c.ToString())
member __.Combine(f,g) = Builder(match f,g with
| Builder(F), Builder(G) ->F.Append(G.ToString())
| Builder(F), StringItem(G)->F.Append(G)
| StringItem(F),Builder(G) ->G.Insert(0, F)
| StringItem(F),StringItem(G)->StringBuilder(F).Append(G))
member __.Delay f = f()
member __.Zero() = StringItem("")
member __.For (xs : 'a seq, f : 'a -> StringBuilderUnion) =
let sb = StringBuilder()
for item in xs do
match f item with
| StringItem(s)-> sb.Append(s)|>ignore
| Builder(b)-> sb.Append(b.ToString())|>ignore
Builder(sb)
let builder1 = new StringBuilderCE()
タイマー機能(各テストは100回実行されることに注意してください):
ここは文字列ビルダの計算式の私の実装です
let duration f =
System.GC.Collect()
let timer = new System.Diagnostics.Stopwatch()
timer.Start()
for _ in 1..100 do
f() |> ignore
printfn "elapsed Time: %i ms" timer.ElapsedMilliseconds
リーダーの特別な場合https://github.com/fsharp/fsharpx/issues/201 –
@MauricioScheffer実際の実装を見てみると、これは貧弱だと思いますそれは 'StringBuilder'クラスのすべてのパフォーマンス上の利点を失うので、文字列ビルダーを実装する方法です。私は、生の 'StringBuilder'を使用することに近いパフォーマンス特性を持つバージョンを作成しようとしています。 – mydogisbox
唯一のパフォーマンスヒットは 'sprintf'です。これは完全にオプションです。 –
- 1. CallerMemberNameAttributeをfで使用することは可能ですか?
- 2. "このホットコードパスでStringBuilderまたはforeachを使用しないでください"
- 3. StringBuilderを使用する際の短所は何ですか?
- 4. F#でClick Once Deploymentを使用することは可能ですか?
- 5. F#からLINQを使用することはできますか?
- 6. StringBuilderを使用してこれをフォーマットするにはどうすればいいですか
- 7. これはWebSocketを使用する正しいシナリオですか?
- 8. Watirを使用しているときに-fパラメータをiexplore.exeに渡すことはできますか?
- 9. リダイレクトにJavascriptを使用することは正しいですか?
- 10. Pythonで正規表現を使用してf-stringを使用する方法
- 11. は960グリッドを使用しているこのコードは正しいですか?
- 12. StringBuilderをテレグラムボットでC#で使用する方法は?
- 13. これは 'partition by'を正しく使用することですか?
- 14. この名前空間の使用は正しいですか?
- 15. CSSを正しく使用することはCSSで重要ですか?
- 16. これはDependency Injectionの正しい使用ですか?
- 17. これはEnumsの正しい使用ですか?
- 18. F#でNullable抽象タイプを使用するにはどうすればよいですか?ここ
- 19. これはAndroidでRealmを使用する正しいアプローチですか?
- 20. これはPythonでマルチプロセッシングキューを使用する正しい方法ですか?
- 21. C#でF#をdllとして使用
- 22. StringBuilderを使用する際の問題
- 23. '\ f'文字は何を使用するのですか?
- 24. Web Developer Express EditionでF#を使用することができます
- 25. ユニットテストでStringBuilderを使用してPInvokingする
- 26. C#を使用しているのは正しいですか?
- 27. StringBuilderで出力パラメータを使用するには?
- 28. のStringBuilder私はStringBuilderのを使用して新しい行を追加しようとするたびだから、私は全く新しい行を取得することはできません新しいライン
- 29. このヘルパーを使用する正しい方法は何ですか?
- 30. これはGebの "at"クロージャを使用する正しい方法ですか?
DLISTを使用できます。http://book.realworldhaskell.org/read/data-structures.html#data.dlist http://jackfoxy.com/f-data-structures/fsharpx-datastructures/#id35 –
私は[不変の文字列ビルダー](http:// stackoverflow。com/a/8346765/162396)を参照してください。 Tomasのテストは18msで実行されます(他のバージョンでも同じタイミングが得られるため、マシンは似ているはずです)。 – Daniel
@MauricioScheffer私は、DListと単純なリストとの比較をどのようにするのかを知りたいと思っています。私は、DListの関数呼び出しにはいくらかのコストもかかっていると思われます... –