模式匹配列表尾元组元素

时间:2013-02-12 18:31:34

标签: algorithm f# compression

我有一些我作为练习写的运行长度编码代码

let rle s = 
    s
    |> List.map (fun x -> (x, 1))
    |> List.fold (fun acc x -> 
        match acc with 
            | [] -> [(x, 1)]
            | h::(x, n) -> h::(x, n+1)
            | h -> h::(x, 1)
        )
    |> List.map (fun (x, n) -> 
        match n with
            | 1 -> x.ToString()
            | _ -> x.ToString() + n.ToString()
        )

模式h::(x, n) -> h::(x, n+1)无法编译。

有谁知道为什么?

3 个答案:

答案 0 :(得分:3)

RLE(笑脸)

let rle (s: string) = 
  let bldr = System.Text.StringBuilder()
  let rec start = function
    | [] -> ()
    | c :: s -> count (1, c) s
  and count (n, c) = function
    | c1 :: s when c1 = c -> count (n+1, c) s
    | s -> Printf.bprintf bldr "%d%c" n c; start s
  start (List.ofSeq s)
  bldr.ToString()

let s1 = "WWWWWWWWWWWWBWWWWWWWWWWWWBBBWWWWWWWWWWWWWWWWWWWWWWWWBWWWWWWWWWWWWWW"
let s2 = "12W1B12W3B24W1B14W"

rle s1 = s2 |> printfn "%b" //"true"

答案 1 :(得分:2)

它无法编译,因为::模式匹配的第二个参数必须是list,但这里它是一个元组。一般来说,您似乎只是误解了headtail。 Head是顶部元素,而tail是以下元素的列表。基本上交换它们可以解决问题:

|> List.fold (fun acc x -> 
    match acc with 
        | [] -> [(x, 1)]
        | (x0, n)::t when x0=x -> (x0, n+1)::t
        | t -> (x, 1)::t
    )
    []

注1:正如@pad注意到的那样,List.fold需要一个参数,一个“bootstrap”累加器开始。显然,它应该只是一个空列表,[] 注意2:您无法直接匹配x。相反,您将其绑定到x0并将x0x进行比较 注3:匹配空列表[]不是必需的,因为它可以很好地处理最后一个模式。

答案 2 :(得分:2)

这不能回答你的问题,但是我觉得很无聊并且编写了一个你可能会发现更具指导性的实现 - 只需在Visual Studio或MonoDevelop中使用调试器逐步完成它。

let rec private rleRec encoded lastChar count charList =
    match charList with
    | [] ->
        // No more chars left to process, but we need to
        // append the current run before returning.
        let encoded' = (count, lastChar) :: encoded

        // Reverse the encoded list so it's in the correct
        // order, then return it.
        List.rev encoded'

    | currentChar :: charList' ->
        // Does the current character match the
        // last character to be processed?
        if currentChar = lastChar then
            // Just increment the count and recurse.
            rleRec encoded currentChar (count + 1) charList'
        else
            // The current character is not the same as the last.
            // Append the character and run-length for the previous
            // character to the 'encoded' list, then start a new run
            // with the current character.
            rleRec ((count, lastChar) :: encoded) currentChar 1 charList'

let rle charList =
    // If the list is empty, just return an empty list
    match charList with
    | [] -> []
    | hd :: tl ->
        // Call the implementation of the RLE algorithm.
        // The initial run starts with the first character in the list.
        rleRec [] hd 1 tl

let rleOfString (str : string) =
    rle (List.ofSeq str)

let rec printRle encoded =
    match encoded with
    | [] ->
        printfn ""
    | (length, c) :: tl ->
        printf "%i%O" length c
        printRle tl

let printRleOfString = rleOfString >> printRle

将代码粘贴到F#interactive中并使用Wikipedia示例run-length encoding

> printRleOfString "WWWWWWWWWWWWBWWWWWWWWWWWWBBBWWWWWWWWWWWWWWWWWWWWWWWWBWWWWWWWWWWWWWW";;
12W1B12W3B24W1B14W
val it : unit = ()