重写msort,因此它在F#中使用模式匹配

时间:2018-01-21 20:33:25

标签: f# pattern-matching

下面的代码是f#中mergesort的代码,我必须重写它,所以它使用模式匹配。

let rec msort xs =
let sz = List.length xs
        if sz < 2 then xs
        else let n = sz / 2
            let ys = xs.[0..n-1]
            let zs = xs.[n..sz-1]
            in merge (msort ys) (msort zs)

到目前为止,我已经到了这里:

let rec msort (vs: int list) =
    let sz = List.length xs
    match xs with 
    | List.length < 2 -> vs 
    | _ -> 
        let n = sz / 2
        let ys = xs.[0..n-1]
        let zs = xs.[n..sz-1]
        in merge (msort ys) (msort zs)

我似乎无法找到更好的方法。有没有人可以帮助我?

2 个答案:

答案 0 :(得分:2)

我可能会这样做:

let rec msort (values: int list) =
    let n = values.Length / 2
    if n = 0 
    then values
    else let rec merge (xs: int list) (ys: int list) =
             match (xs, ys) with
             | ([], ys) -> ys
             | (xs, []) -> xs
             | (x :: xs1, y :: ys1) ->
                  if x < y
                  then x :: merge xs1 ys
                  else y :: merge xs ys1        

         let (first, second) = values |> List.splitAt n
         merge (msort first) (msort second)

模式匹配对于初始逻辑(列表的长度,长度为0和1的早期出口)并不太有用,但我认为在匹配子列表后的情况时,它更具可读性。分裂。即使如此,msort部分中只有一个if / then,如果您真的想要它可以替换为模式匹配:

let rec msort (values: int list) =
    match values.Length / 2 with
    | 0 -> values
    | n -> 
        let rec merge (xs: int list) (ys: int list) =
            match (xs, ys) with
            | ([], ys) -> ys
            | (xs, []) -> xs
            | (x :: xs1, y :: ys1) ->
                if x < y
                then x :: merge xs1 ys
                else y :: merge xs ys1        

        let (first, second) = values |> List.splitAt n
        merge (msort first) (msort second)

这只会在if/then实施中仅留下x<y merge,我不会改变它。

答案 1 :(得分:1)

几乎相同,但我建议自定义拆分:

let split2 (li: int list) =
    let n = (List.length li) / 2
    let rec looprec (len: int) (l1: int list) (l2: int list) =
         if len > 0 then
            match l1 with 
               | x::tail -> looprec (len-1) tail (x::l2)
               | _ -> (List.rev l2, l1)               
         else 
           (List.rev l2, l1)
     in looprec n li []

let rec merge (l1: int list) (l2: int list) =
    match (l1,l2) with
        | (x,[]) -> x
        | ([],y) -> y
        | (x::tx,y::ty) ->
            if x <= y 
            then x::merge tx l2
            else y::merge l1 ty

let rec msort (li: int list) = 
    match li with
        | [] -> []
        | [x] -> [x]
        | _ -> let (l1,l2) = split2 li
               in merge (msort l1) (msort l2)

let d=  msort [3;20;12]

printfn "%A" d