F# 只过滤掉列表中的第一次出现
F# filter out only first occurrence from list
我有一个列表,我想删除符合某些条件的元素,但只删除一个元素。
let items = [1;2;3]
let predicate x =
x >= 2
let result = items |> List.fold ...
// result = [1;3]
如何用[1;3]实现方法返回列表?
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
状态是一个元组。第一个元素是一个布尔标志,指示我们是否已经从列表中删除了一些项目。第二个元素是一个选项:一些当我们想要发出该项目时,None 否则。
最后一行从状态中获取第二个元素,并为每个状态发出包装值(在 Some 的情况下)或什么也不做(在 None 的情况下)。
您可以使用通用递归函数
let rec removeFirst predicate = function
| [] -> []
| h :: t when predicate h -> t
| h :: t -> h :: removeFirst predicate t
或者尾递归(如果你担心堆栈溢出)
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 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
我有一个列表,我想删除符合某些条件的元素,但只删除一个元素。
let items = [1;2;3]
let predicate x =
x >= 2
let result = items |> List.fold ...
// result = [1;3]
如何用[1;3]实现方法返回列表?
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
状态是一个元组。第一个元素是一个布尔标志,指示我们是否已经从列表中删除了一些项目。第二个元素是一个选项:一些当我们想要发出该项目时,None 否则。
最后一行从状态中获取第二个元素,并为每个状态发出包装值(在 Some 的情况下)或什么也不做(在 None 的情况下)。
您可以使用通用递归函数
let rec removeFirst predicate = function
| [] -> []
| h :: t when predicate h -> t
| h :: t -> h :: removeFirst predicate t
或者尾递归(如果你担心堆栈溢出)
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 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