2014-01-16 54 views
2

我想要創建一個函數,它接受一個列表並返回一個帶有刪除重複項的列表。F#使用函數從列表中刪除重複項

let removedupes list1 = 
    let list2 = [] 
    let rec removeduprec list1 list2 = 
    match list1 with 
    | [] -> list2 
    | head :: tail when mem list2 head = false -> head :: removeduprec tail list2 
    | _ -> removeduprec list1.Tail list2 
    removeduprec list1 list2 

進出口使用這種「MEM」功能走線槽清單,看看是否值已經存在,在這種情況下,我會繼續用遞歸。

let rec mem list x = 
    match list with 
    | [] -> false 
    | head :: tail -> 
    if x = head then true else mem tail x 

當我測試此代碼,我得到

let list1 = [ 1; 2; 3; 4; 5; 2; 2; 2] 
removedups list1;; 
val it : int list = [1; 2; 3; 4; 5; 2; 2; 2] 

林認爲「頭:: removeduprec尾列表2」,但即時通訊相當新的F#所以不能完全肯定這是如何工作。

+1

更簡單的方法在這裏:http://stackoverflow.com/questions/6842466/ –

+0

設置不包含重複項。也許從列表創建集? – Alexan

+0

@Alex - 我鏈接的其中一個答案使用set。構造函數爲你刪除重複項。 –

回答

5

我重寫了一些邏輯,使事情變得更簡單。問題是,你需要的東西添加到list2,因爲它被創造,而不是事後 - 我搬到了::到裏面調用,像這樣

let rec mem list x = 
    match list with 
    | [] -> false 
    | head :: tail -> 
    if x = head then true else mem tail x 

let removedupes list1 = 
    let rec removeduprec list1 list2 = 
    match list1 with 
    | [] -> list2 
    | head :: tail when mem list2 head = false -> removeduprec tail (head::list2) 
    | h::t -> removeduprec t list2 
    removeduprec list1 [] 
5

stackoverflow.com/questions/6842466John's辦法的補充;不太習慣,但快速和明顯的:

let removeDups is = 
    let d = System.Collections.Generic.Dictionary() 
    [ for i in is do match d.TryGetValue i with 
        | (false,_) -> d.[i] <-(); yield i 
        | _ ->() ] 

它消除了從具有10萬個在不同值百萬元的名單副本由

Real: 00:00:00.182, CPU: 00:00:00.171, GC gen0: 14, gen1: 1, gen2: 0 

更新:以下代替Dictionary提升使用HashSetildjarn's評論性能約相同數據兩次攤銷:

Real: 00:00:00.093, CPU: 00:00:00.093, GC gen0: 2, gen1: 1, gen2: 0 

相反,using the set字面上相同的測試情況下,建議缺點表現27X

Real: 00:00:02.788, CPU: 00:00:02.765, GC gen0: 100, gen1: 21, gen2: 1 
+0

爲什麼字典而不是HashSet? – ildjarn

+0

是的,你可以使用一個集合,而'HashSet'很可能是LINQ的'Distinct'(也可能是'Seq.distinctBy')在內部使用的。 –

+0

@ildjarn:謝謝,不知何故錯過了。我已經更新了我的答案,並使用'HashSet'和'Dictionary'與F#'set'進行了性能比較。 –

2

約翰答案可能是你在找什麼 - 它表明解決問題的慣用功能性的方式。但是,如果你不想自己實現的功能,最簡單的方法是打開列表轉換爲一組(其中不能包含重複),然後返回到列表:

let list1 = [ 1; 2; 3; 4; 5; 2; 2; 2] 
let list2 = List.ofSeq (set list1) 

這可能是最短的解決方案:-)與John的版本有一點不同之處在於,這並不保留列表的原始順序(它實際上對它進行排序)。

+2

要保留原始順序,您還可以使用: let list2 = list1 |> Seq.distinct |> Seq.toList。 –

+0

短是好.. – nicolas

0

只是爲了完整性:在F#4.0中List模塊現在有distinct函數完全符合OP的要求。

List.distinct [1; 2; 2; 3; 3; 3];; 
val it : int list = [1; 2; 3;]