我正在寻找StringBuilder或同等功能的功能(如in,non-imperative)实现。我已经看到了几个功能数组实现,但它们本身不支持插入。开源,非(L?A?)GPL的奖金,F#的奖金,但如果需要,我可以从Haskell / OCaml / SML翻译。
欢迎使用算法的建议。
答案 0 :(得分:3)
StringBuilder
优于string
的优势在于最小化分配。它预先分配一个缓冲区以避免为每个插入/追加分配。这需要可变性 - 某些对象必须拥有(并改变)缓冲区。
顺便提一下,System.String
已经符合(我能做到的)你的描述:它是不可变的,支持连接,insertionMSDN和removalMSDN。
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)
用法
let bldr =
StringBuilder.create "abcdef"
|> StringBuilder.insert 1 "xyz"
|> StringBuilder.append "123"
|> StringBuilder.remove 1 2
bldr.ToString() //azbcdef123
它是持久的,插入是O(1)。
答案 1 :(得分:0)
我不知道任何可以完全按照您的要求执行的实现。但是,我认为你不能在结果上获得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
,因此数据结构仍然是纯粹的功能。