如何在不使用引用的情况下删除F#序列中的重复项

时间:2011-07-27 09:55:48

标签: f#

我有一个已排序的序列,想要浏览它并返回序列中的唯一条目。我可以使用以下函数来完成它,但它使用引用变量,我不认为这是解决问题的正确方法。

    let takeFirstCell sectors = 
        let currentRNCId = ref -1
        let currentCellId = ref -1
        seq {
            for sector in sectors do
                if sector.RNCId <> !currentRNCId || sector.CellId <> !currentCellId then
                    currentRNCId := sector.RNCId
                    currentCellId := sector.CellId
                    yield sector
        }

我怎样才能以功能的方式做到这一点?

6 个答案:

答案 0 :(得分:12)

[1;1;1;2;2;2;3;3;3]
|> Seq.distinctBy id
|> printfn "%A"

答案 1 :(得分:7)

Seq.distinct (1::[1..5])返回seq [1; 2; 3; 4; 5]。那是你的意思吗?

答案 2 :(得分:5)

distinctdistinctBy都使用Dictionary,因此需要散列和一些内存来存储唯一的项目。如果您的序列已经排序,您可以使用以下方法(与您的类似)。它几乎快两倍,并且具有恒定的内存使用,使其可用于任何大小的序列。

let distinctWithoutHash (items:seq<_>) =
  seq {
    use e = items.GetEnumerator()
    if e.MoveNext() then
      let prev = ref e.Current
      yield !prev
      while e.MoveNext() do
        if e.Current <> !prev then 
          yield e.Current
          prev := e.Current
  }

let items = Seq.init 1000000 (fun i -> i / 2)
let test f = items |> f |> (Seq.length >> printfn "%d")

test Seq.distinct        //Real: 00:00:01.038, CPU: 00:00:01.435, GC gen0: 47, gen1: 1, gen2: 1
test distinctWithoutHash //Real: 00:00:00.622, CPU: 00:00:00.624, GC gen0: 44, gen1: 0, gen2: 0

我无法找到一种方法来使用mutable而不是ref s(缺少手工编码的枚举器),我肯定会大大加快它的速度(我试过了 - 没有区别)。

答案 3 :(得分:4)

使用如下序列初始化一个唯一的集合(如集合):

set [1; 2; 3; 3; 4; 5; 5];;
=> val it : Set<int> = set [1; 2; 3; 4; 5]

答案 4 :(得分:1)

下面的解决方案保留元素的顺序,并仅返回泛型列表中元素的第一次出现。当然,这会生成一个删除了多余项目的新列表。

//  ****  Returns a list having subsequent redundant elements removed
let removeDuplicates(lst : 'a list) = 
    let f item acc =
        match acc with 
        | [] -> [item]
        | _ ->
            match List.exists(fun x -> x = item) acc with
            | false -> item :: acc
            | true -> acc
    lst 
    |> List.rev
    |> fun x -> List.foldBack f x []
    |> List.rev
//  **** END OF FUNCTION removeDuplicates

val removeDuplicates : 'a list -> 'a list when 'a : equality
val testList : int list = [1; 4; 3; 1; 2; 2; 1; 1; 3; 4; 3]
val tryAbove : int list = [1; 4; 3; 2]

答案 5 :(得分:1)

在我的情况下,我无法使用Seq.distinct,因为我需要保留列表元素的顺序。 我使用了来自http://ocaml.org/learn/tutorials/99problems.html的解决方案。 我认为这很短暂

let rec compress = function
    | a :: (b :: _ as t) -> if a = b then compress t else a :: compress t
    | smaller -> smaller