查找(并删除)数组中的重复对

时间:2013-12-17 00:56:42

标签: f#

我想要一种摆脱数组中重复对的方法。对于我的问题,对将是连续的,并且最多只有一个重复对。

我目前的实施似乎太复杂了。元素3和4形成了我在下面arr1中称为重复对的内容。作为一对,它们只在所需的输出中出现一次,arr2。有哪些更有效的方法?

let arr1=[|4; 2; 3; 4; 3; 4; 1|]
let n=arr1.Length
let iPlus2IsEqual=Array.map2 (fun x y -> x=y) arr1.[2..] arr1.[..(n-3)]
let consecutive=Array.map2 (fun x y -> x && y) iPlus2IsEqual.[1..] iPlus2IsEqual.[..(n-4)] |> Array.tryFindIndex (fun x -> x)
let dup=if consecutive.IsSome then consecutive.Value+1 else n-1
let arr2=if dup>=n-3 then arr1.[..dup] else Array.append arr1.[..dup] arr1.[(dup+3)..]

>
val arr2 : int [] = [|4; 2; 3; 4; 1|]

3 个答案:

答案 0 :(得分:2)

我们可以像这样使用递归(它也会免费获得多次重复)

let rec filterrepeats l =
    match l with
    |a::b::c::d::t when a=c && b=d -> a::b::(filterrepeats t)
    |h::t          ->h::(filterrepeats t)
    |[] -> []

> filterrepeats [4;2;3;4;3;4;1];;
val it : int list = [4; 2; 3; 4; 1]

这适用于列表,因此您需要在运行之前添加对Array.toList的调用。

上面不是尾递归的,因为编译器在函数调用之后才知道h::(filterrepeats t)右边的内容。你可以使用像这样的累加器来解决这个问题:

let rec filterrepeats l  =
    let rec loop l acc =
        match l with
        |a::b::c::d::t when a=c && b=d ->loop t (b::a::acc)
        |h::t          ->loop t (h::acc)
        |[] -> acc
    loop (List.rev l) []

答案 1 :(得分:2)

对于大型阵列,这比您的解决方案快13倍:

let inline tryFindDuplicatedPairIndex (xs: _ []) =
  let rec loop i x0 x1 x2 =
    if i < xs.Length-4 then
      let x3 = xs.[i+3]
      if x0=x2 && x1=x3 then Some i else
        loop (i+1) x1 x2 x3
    else None
  if xs.Length < 4 then None else
    loop 0 xs.[0] xs.[1] xs.[2]

let inline removeDuplicatedPair (xs: _ []) =
  match tryFindDuplicatedPairIndex xs with
  | None -> Array.copy xs
  | Some i ->
      let ys = Array.zeroCreate (xs.Length-2)
      for j=0 to i-1 do
        ys.[j] <- xs.[j]
      for j=i+2 to xs.Length-1 do
        ys.[j-2] <- xs.[j]
      ys

我使用inline并单独测试元素(即而不是作为元组:(x0,x1) = (x2,x3))来尝试阻止=成为通用的相等测试,因为这非常慢。我已经重复使用了从一次迭代到下一次迭代的先前数组查找。如果输出与输入相同,则复制输入数组,否则预先分配具有n-2元素的数组。我已经将复制手动滚动到我预先分配的数组,以避免产生任何垃圾(例如,而不是两片Array.append)。

答案 2 :(得分:0)

没有大型列表堆栈溢出(长度&gt; = 100K)并删除所有重复对

let rec distinctPairs list = 
    List.foldBack (fun x (l,r) -> x::r, l) list ([],[])
    |> fun (odds, evens) -> List.zip odds evens 
    |> Seq.distinct

不是很快,1M列表需要500毫秒,反正更快?

仅适用于长度均匀的列表