2017-09-04 27 views

Trả lời

6

Bạn có thể sử dụng một hàm đệ quy chung

let rec removeFirst predicate = function 
    | [] -> [] 
    | h :: t when predicate h -> t 
    | h :: t -> h :: removeFirst predicate t 

hoặc một cái đuôi một đệ quy (nếu bạn sợ một stack overflow)

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 
+0

Điều khoản bảo vệ có thể tốt đẹp, nhưng trong trường hợp này tôi nghĩ rằng chúng làm cho nó khó hiểu hơn. Tôi nghĩ chỉ là '| h :: t -> nếu vị từ h sau đó (List.rev acc) @ t else vòng lặp (h :: acc) t' là rõ ràng hơn. – mydogisbox

+0

Lợi thế của câu trả lời này là nó ngừng xử lý khi đạt được giá trị khớp đầu tiên để có thể tiết kiệm rất nhiều công việc. – TheQuickBrownFox

+0

Trong phiên bản đệ quy đuôi, bạn có thể thay đổi trường hợp '[]' để trả về 'danh sách' đầu vào thay vì đảo ngược bộ tích lũy, mà chỉ là danh sách đảo ngược. – TheQuickBrownFox

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 

Trạng thái là bộ tuple. Yếu tố đầu tiên là cờ Boolean cho biết chúng tôi đã xóa một số mục khỏi danh sách. Yếu tố thứ hai là một tùy chọn: Một số khi chúng tôi muốn phát ra mục, Không có cách nào khác.

Dòng cuối cùng lấy các phần tử thứ hai từ các trạng thái và cho mỗi phần tử phát ra giá trị được bao bọc (trong trường hợp Một số) hoặc không làm gì cả (trong trường hợp Không có).

+0

Điều này chạy chậm nhất trong các thử nghiệm của tôi. – Soldalma

2

Đây là một thay thế ngắn, mà trong thử nghiệm của tôi là nhanh hơn so với những đề xuất khác được đề xuất cho đến thời điểm này:

let removeFirst p xs = 
    match List.tryFindIndex p xs with 
    | Some i -> List.take i xs @ List.skip (i+1) xs 
    | None -> xs 
0

Hướng tới giải pháp trực quan.

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 

Để biết hiệu suất (danh sách dài).

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 
Các vấn đề liên quan