私はリストを持っていますが、いくつかの基準に合った要素を削除したいが、要素を1つだけ削除したい。F#リストからの最初の出現をフィルタにかける
let items = [1;2;3]
let predicate x =
x >= 2
let result = items |> List.fold ...
// result = [1;3]
[1; 3]でリストを返す方法を実現するにはどうすればよいですか?
私はリストを持っていますが、いくつかの基準に合った要素を削除したいが、要素を1つだけ削除したい。F#リストからの最初の出現をフィルタにかける
let items = [1;2;3]
let predicate x =
x >= 2
let result = items |> List.fold ...
// result = [1;3]
[1; 3]でリストを返す方法を実現するにはどうすればよいですか?
あなたは
let rec removeFirst predicate = function
| [] -> []
| h :: t when predicate h -> t
| h :: t -> h :: removeFirst predicate t
かここで末尾再帰1(あなたは、スタックオーバーフローを恐れている場合)
let removeFirst predicate list =
let rec loop acc = function
| [] -> List.rev acc
| h :: t when predicate h -> (List.rev acc) @ t
| h :: t -> loop (h :: acc) t
loop [] list
let result =
items
|>List.scan (fun (removed, _) item ->
if removed then true, Some(item) //If already removed, just propagate
elif predicate item then true, None //If not removed but predicate matches, don't propagate
else false, Some(item)) //If not removed and predicate doesn't match, propagate
(false, None)
|>List.choose snd
状態はタプルです。最初の要素は、すでにリストから項目を削除したかどうかを示すブール値のフラグです。 2番目の要素はオプションです:項目を出そうとするときには、そうでなければNoneを選択します。
最後の行は状態から2番目の要素を取り、それぞれがラップされた値(Someの場合)を出すか、何もしません(Noneの場合)。
これはテストで最も遅く実行されました。 – Soldalma
は私のテストで速かった短い代わり、ある一般的な再帰関数を使用することができますこれまでに提案された他のものよりも:
let removeFirst p xs =
match List.tryFindIndex p xs with
| Some i -> List.take i xs @ List.skip (i+1) xs
| None -> xs
直感的な解決策を目指します。
let removeAt index list =
let left, right = List.splitAt index list
left @ (List.skip 1 right)
let removeFirst predicate list =
match List.tryFindIndex predicate list with
| Some index -> removeAt index list
| None -> list
パフォーマンス(長いリスト)の場合。
let removeFirst predicate list =
let rec finish acc rem =
match rem with
| [] -> acc
| x::xs -> finish (x::acc) xs
and find l p acc rem =
match rem with
| [] -> l
| x::xs ->
if p x then finish xs acc
else find l p (x::acc) xs
find list predicate [] list
ガード句はうまくいくかもしれませんが、この場合はもっと紛らわしいと思います。私はちょうど '| h :: t - >述語hならば(List.rev acc)@ else else(h :: acc)t'がより明確であれば。 – mydogisbox
この回答の利点は、最初に一致する値に達したときに処理が停止し、多くの作業を節約できることです。 – TheQuickBrownFox
テール再帰的なバージョンでは、アキュムレータを逆転させるのではなく、 '[]'の大文字と小文字を変更して入力 'list'を返すことができます。 – TheQuickBrownFox