よりエレガントな機能液:
let duplicates xs =
Seq.scan (fun xs x -> Set.add x xs) Set.empty xs
|> Seq.zip xs
|> Seq.choose (fun (x, xs) -> if Set.contains x xs then Some x else None)
がこれまで見て、すべての要素のセットを蓄積するscan
を使用します。次に、zip
を使用して、各要素をその前の要素のセットと結合します。最後に、choose
を使用して、前に見た要素のセット、つまり重複している要素に含まれる要素を除外します。
EDIT
実は私のオリジナルの答えは完全に間違っていました。まず、出力に重複を必要としません。第二に、パフォーマンスが必要です。ここで
はあなたが後にしているアルゴリズムを実装して、純粋に機能的なソリューションです:
let duplicates xs =
(Map.empty, xs)
||> Seq.scan (fun xs x ->
match Map.tryFind x xs with
| None -> Map.add x false xs
| Some false -> Map.add x true xs
| Some true -> xs)
|> Seq.zip xs
|> Seq.choose (fun (x, xs) ->
match Map.tryFind x xs with
| Some false -> Some x
| None | Some true -> None)
これは、各要素が一回または多数回の前に見て、それならば要素を発してきたかどうかを追跡するためにマップを使用しています以前に一度だけ見られた、すなわちそれが初めて複製されたことが見られる。これはあなたの他の回答(執筆時)のいずれよりも約2 ×高速である
let duplicates (xs: _ seq) =
seq { let d = System.Collections.Generic.Dictionary(HashIdentity.Structural)
let e = xs.GetEnumerator()
while e.MoveNext() do
let x = e.Current
let mutable seen = false
if d.TryGetValue(x, &seen) then
if not seen then
d.[x] <- true
yield x
else
d.[x] <- false }
:ここ
は速い不可欠バージョンです。シーケンス内の要素を列挙するfor x in xs do
ループを使用し
は直接GetEnumerator
を使用するよりも実質的に遅いですが、あなた自身のEnumerator
を生成することyield
で計算式を使用するよりもはるかに高速ではありません。 Dictionary
のTryGetValue
メンバーは、私は(彼/彼女の答えでKVBにより、使用)のF#が提供するTryGetValue
延長部材は、その戻りタプルを割り振るのに対し、スタックに割り当てられた値を変異させることにより、内側のループで割り当てが行われないようにする
注意。
[参照を使用せずにF#シーケンスで重複を削除するにはどうすればいいですか?](http://stackoverflow.com/questions/6842466/how-can-i-remove-duplicates-in-an-f-sequence - without-using-references) – gradbot
実際、それは逆です。私は重複が欲しいだけです。 – Daniel
ええ、あなたはすでに訪れた値をどのように保存したいですか?セット?辞書? – gradbot