2017-02-27 133 views
3

我想要做的是刪除字符串中特定給定字符的重複項,但讓第一個字符保留。即:F# - 刪除字符串中的第一個字符後的重複字符

let myStr = "hi. my .name." 

//a function that gets a string and the element to be removed in the string 
someFunc myStr "." 

其中someFunc返回如下字符串showen:

"hi. my name" 

這是很容易從一個字符串中刪除重複的,但有沒有辦法刪除重複的,但讓第一個重複的元素留在字符串中?

+0

不熟悉F#但是,您可以通過迭代字符串來創建字符列表。使用Contains方法來檢查一個字符是否已經存在。如果是這樣,跳過,否則添加到列表 – Laazo

+0

Azola的想法看起來不錯,但我建議做一個集合,因爲'List.contains'是O(N)。使用['Set.ofSeq'](https://msdn.microsoft.com/en-us/visualfsharpdocs/conceptual/set.ofseq%5B't%5D-function-%5Bfsharp%5D),然後你應該能夠在O(1)時間內進行查找。 – rmunn

+5

你能告訴我們你試過了什麼嗎? – TheInnerLight

回答

4

這裏有一個辦法:

let keepFirst c s = 
    Seq.mapFold (fun k c' -> (c', k||c<>c'), k&&c<>c') true s 
    |> fst 
    |> Seq.filter snd 
    |> Seq.map fst 
    |> Array.ofSeq 
    |> System.String 

let example = keepFirst '.' "hi. my .name." 
2
let someFunc (str : string) c = 
    let parts = str.Split([| c |]) 
    if Array.length parts > 1 then 
     seq { 
      yield Array.head parts 
      yield string c 
      yield! Array.tail parts 
     } 
     |> String.concat "" 
    else 
     str 

請注意,該字符是以char而不是字符串形式給出的。

2
let someFunc chr (str:string) = 
    let rec loop (a: char list) b = function 
     | [] -> a |> List.rev |> System.String.Concat 
     | h::t when h = chr -> if b then loop a b t 
           else loop (h::a) true t 
     | h::t -> loop (h::a) b t 
    loop [] false (str.ToCharArray() |> Array.toList) 

請注意,該字符是以char而不是字符串形式給出的。

編輯:另一種方法是使用正則表達式

open System.Text.RegularExpressions 

let someOtherFunc c s = 
    let pat = Regex.Escape(c) 
    Regex.Replace(s, sprintf "(?<=%s.*)%s" pat pat, "") 

需要注意的是,在這種情況下,字符作爲字符串。

編輯2:

let oneMoreFunc (c:char) (s:string) = 
    let pred = (<>) c 
    [ s |> Seq.takeWhile pred 
     seq [c] 
     s |> Seq.skipWhile pred |> Seq.filter pred ] 
    |> Seq.concat 
    |> System.String.Concat 
0

當設計一個功能,可考慮從製造它的參數一般收益。要通過迭代傳遞狀態,禁止可變變量,Seq.scan可能是一個選擇的武器。它摺疊成新狀態的元組和一個選項,然後Seq.choose去掉狀態和不需要的元素。

在功能構建模塊方面,使其接受謂詞功能'a -> bool並讓它返回函數seq<'a> -> seq<'a>。然後

let filterDuplicates predicate = 
    Seq.scan (fun (flag, _) x -> 
     let p = predicate x in flag || p, 
     if flag && p then None else Some x) (false, None) 
    >> Seq.choose snd 

這可以很容易地重用做其他事情,以及像0 together with odd numbers

filterDuplicates (fun i -> i % 2 = 0) [0..10] 
// val it : seq<int> = seq [0; 1; 3; 5; ...] 

提供與對等式操作符的調用,並送入的System.String構造函數,你會得到你想要的簽名,char -> seq<char> -> System.String附近。

let filterDuplicatesOfChar what s = 
    System.String(Array.ofSeq <| filterDuplicates ((=) what) s) 
filterDuplicatesOfChar '.' "hi. my .name." 
// val it : string = "hi. my name" 
相關問題