我想要一种摆脱数组中重复对的方法。对于我的问题,对将是连续的,并且最多只有一个重复对。
我目前的实施似乎太复杂了。元素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|]
答案 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毫秒,反正更快?
仅适用于长度均匀的列表