2017-09-04 9 views
5

से केवल पहली घटना फ़िल्टर करें मेरे पास एक सूची है और मैं कुछ मानदंडों से मेल खाने वाला तत्व निकालना चाहता हूं लेकिन केवल एक तत्व को हटा सकता हूं।एफ # सूची

let items = [1;2;3] 

let predicate x = 
    x >= 2 

let result = items |> List.fold ... 
// result = [1;3] 

[1; 3] के साथ विधि वापसी सूची कैसे प्राप्त करें?

उत्तर

6

आप (यदि आप एक ढेर अतिप्रवाह डर) एक सामान्य पुनरावर्ती क्रिया

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

गार्ड क्लॉज अच्छा हो सकता है, लेकिन इस मामले में मुझे लगता है कि वे इसे और अधिक भ्रमित कर देते हैं। मुझे लगता है कि बस '| एच :: टी -> यदि एच को पूर्व निर्धारित करें (List.rev acc) @ t else loop (h :: acc) t' अधिक स्पष्ट है। – mydogisbox

+0

इस उत्तर का एक लाभ यह है कि जब पहला मिलान मूल्य पहुंच जाता है तो यह प्रसंस्करण बंद कर देता है ताकि यह बहुत से काम को बचा सके। – TheQuickBrownFox

+0

पूंछ-पुनरावर्ती संस्करण में आप '[] 'केस को संचयक को उलट करने के बजाय इनपुट' सूची' वापस करने के लिए बदल सकते हैं, जो कि वैसे भी उलट सूची है। – 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 

राज्य एक ट्यूपल है। पहला तत्व एक बूलियन ध्वज है जो दर्शाता है कि क्या हमने सूची से कुछ आइटम हटा दिया है या नहीं। दूसरा तत्व एक विकल्प है: कुछ जब हम आइटम को उत्सर्जित करना चाहते हैं, अन्यथा कोई नहीं।

अंतिम पंक्ति राज्यों से दूसरे तत्व लेती है और उनमें से प्रत्येक के लिए लपेटा हुआ मूल्य (कुछ के मामले में) उत्सर्जित करता है या कुछ भी नहीं (किसी के मामले में) नहीं करता है।

+0

यह मेरे परीक्षणों में सबसे धीमा दौड़ गया। – Soldalma

2

यहाँ एक छोटी विकल्प है, जो मेरे परीक्षण में तेजी से किया गया है अब तक प्रस्तावित अन्य लोगों की तुलना में:

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

एक सहज समाधान के लिए लक्ष्य।

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