F# 是否有.NET StringBuilder功能版本的开源(非GPL)实现?
我正在寻找StringBuilder或同等产品的功能性(如非强制性)实现。我见过几个函数数组的实现,但它们不支持本机插入。开源、非-(L?A?)GPL的奖金,F#的奖金,但如果需要,我可以从Haskell/OCaml/SML进行翻译F# 是否有.NET StringBuilder功能版本的开源(非GPL)实现?,f#,stringbuilder,F#,Stringbuilder,我正在寻找StringBuilder或同等产品的功能性(如非强制性)实现。我见过几个函数数组的实现,但它们不支持本机插入。开源、非-(L?A?)GPL的奖金,F#的奖金,但如果需要,我可以从Haskell/OCaml/SML进行翻译 欢迎对算法提出建议。StringBuilder相对于string的优势在于最小化分配。它预先分配一个缓冲区,以避免为每次插入/追加分配缓冲区。这需要可变性——某些对象必须拥有(并改变)缓冲区 顺便说一句,System.String已经符合(我能理解的)您的描述:它是
欢迎对算法提出建议。
StringBuilder
相对于string
的优势在于最小化分配。它预先分配一个缓冲区,以避免为每次插入/追加分配缓冲区。这需要可变性——某些对象必须拥有(并改变)缓冲区
顺便说一句,System.String
已经符合(我能理解的)您的描述:它是不可变的,支持连接,并且
更新
托马斯的想法引起了我的兴趣。考虑到他的想法,以下是我的想法
type StringBuilder =
private
| Empty
| StringBuilder of int * string * int * StringBuilder
member this.Length =
match this with
| Empty -> 0
| StringBuilder(_, _, n, _) -> n
override this.ToString() =
let rec rev acc = function
| Empty -> acc
| StringBuilder(idx, str, _, bldr) -> rev ((idx, str)::acc) bldr
let buf = ResizeArray(this.Length)
for idx, str in rev [] this do buf.InsertRange(idx, str)
System.String(buf.ToArray())
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
[<RequireQualifiedAccess>]
module StringBuilder =
let empty = Empty
let length (bldr:StringBuilder) = bldr.Length
let insert index str bldr =
if index < 0 || index > (length bldr) then invalidArg "index" "out of range"
StringBuilder(index, str, str.Length + bldr.Length, bldr)
let create str = insert 0 str empty
let append str bldr = insert (length bldr) str bldr
let remove index count (bldr:StringBuilder) = create <| bldr.ToString().Remove(index, count)
它是持久性的,插入是O(1)。我不知道有什么实现能完全满足您的要求。然而,我不认为你能得到插入的O(1)复杂度(在任意索引处)和迭代结果的O(n)复杂度 如果您愿意牺牲插入的复杂性,那么可以按照Daniel的建议使用
string
。另一方面,如果您愿意牺牲toString
的复杂性,那么您可以通过使用字符串和索引列表在任意位置插入O(1)来生成不可变的数据结构:
type InsertList = IL of (int * string) list
// Insert string 'str' at the specified index
let insertAt idx str (IL items) = IL (idx, str)::items
// Create insert list from a string
let ofString str = IL [str]
转换为字符串有点棘手。但是,我认为通过使用可变的
LinkedList
并通过从末尾重复插入,在正确的位置插入单个字符,可以获得O(n log n)的复杂性。LinkedList
的使用将被本地化为toString
,因此数据结构仍然是纯功能的。您希望从StringBuilder获得哪些功能和性能?O(1)insert和O(n)toArray?我对性能不是太挑剔,但是是的,理想情况下,O(1)insert和O(n)转换回seq/stream/array。我怀疑O(1)insert在任意位置是否适用于功能数据结构。标准stringbuilder到底出了什么问题?还有,您所说的“功能性”到底是什么意思?Persistent?Immutable是另一个常用于非破坏性数据类型的名称。到字符串的最小转换至少为O(n),因为您必须反转列表以处理insertAt 0“World”
然后insertAt 0“Hello”
,然后我认为最好的方法是使用稳定的排序,我怀疑最好的情况可能是O(n*log n*m),其中有m
插入,因为您必须处理重叠。我尝试实现您的想法,并将其包含在我的答案中。它看起来像你想的那样吗?插入实际上不是O(1),它是O(插入次数),由于长度检查,我认为ToString
的O也太低了,因为至少你是通过idx有效排序的,这将使它成为O(n logn)你是对的。您可以放弃insert上的长度检查,并插入ToString
,使其成为O(1)。即使检查结果是O(插入),它还是非常有效的。我很确定string.Length
是O(1)。有一个递归步骤,你把所有长度加起来,使长度为O(n.insertions)。你是对的,它是O(插入),但是因为string.Length
是O(1),所以它非常便宜。
type InsertList = IL of (int * string) list
// Insert string 'str' at the specified index
let insertAt idx str (IL items) = IL (idx, str)::items
// Create insert list from a string
let ofString str = IL [str]