我想创建一个获取列表的函数,并返回一个包含已删除重复项的列表。
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]
我认为" head :: removeduprec tail list2",但我对f#很新,所以不能完全确定它是如何工作的。
答案 0 :(得分:6)
我重写了一些逻辑以使事情更简单。问题是您需要在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 []
答案 1 :(得分:5)
stackoverflow.com/questions/6842466和John'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
| _ -> () ]
它通过
从具有100000个不同值的1000000个元素的列表中删除重复项 Real: 00:00:00.182, CPU: 00:00:00.171, GC gen0: 14, gen1: 1, gen2: 0
更新:使用HashSet
代替Dictionary
发表Real: 00:00:00.093, CPU: 00:00:00.093, GC gen0: 2, gen1: 1, gen2: 0
评论,代替Real: 00:00:02.788, CPU: 00:00:02.765, GC gen0: 100, gen1: 21, gen2: 1
提升相同数据的两倍摊销效果:
{{1}}
相反,ildjarn's字面意思与同一测试案例的建议相比,性能 27x :
{{1}}
答案 2 :(得分:2)
约翰的回答可能就是你要找的 - 它显示了一种解决问题的惯用功能方式。但是,如果您不想自己实现该功能,最简单的方法是将列表转换为 set (不能包含重复项),然后返回列表:
let list1 = [ 1; 2; 3; 4; 5; 2; 2; 2]
let list2 = List.ofSeq (set list1)
这可能是最短的解决方案:-)与John的版本有一点不同之处在于它不保留列表的原始排序(实际上是对它进行排序)。
答案 3 :(得分:0)
为了完整起见:在F#4.0中,List
模块现在具有distinct
功能,正好与OP一样。
List.distinct [1; 2; 2; 3; 3; 3];;
val it : int list = [1; 2; 3;]