2013-02-12 90 views
0

我有我写了一个练习模式匹配列表尾部元组元素

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)无法编译一些运行长度编码代码。

有谁知道为什么?

+1

@pad嗯countBy似乎只是做了直方图。它似乎没有考虑到每个元素的邻域条件。 – jameszhao00 2013-02-12 19:18:29

+0

你是对的。需要一些时间来回忆一下RLE的内容。 – pad 2013-02-12 19:22:49

回答

2

它无法编译,因为::模式匹配的第二个参数必须是list,但在这里它是一个元组。一般来说,你似乎只是误解了headtail。 Head是最上面的元素,而尾是以下元素的列表。从本质上讲交换他们的伎俩:

|> 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需要多一个说法,“引导”累加器开始。显然,它应该只是一个空列表,[]
注2:不能直接匹配x。相反,您将其绑定到x0并将x0x进行比较。
注3:匹配空列表[]没有必要,因为它会愉快地使用最后一种模式。

+2

他忘记了'List.fold'上的第二个参数。你可能应该添加它。 – pad 2013-02-12 19:02:15

+2

最初的'map'也不需要。你应该注意到,用这种方法(我同意),如果你想要它的顺序与输入列表的顺序相匹配,你需要反转结果列表。 – latkin 2013-02-12 19:05:48

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#互动性和使用run-length encoding维基百科的例子:

> printRleOfString "WWWWWWWWWWWWBWWWWWWWWWWWWBBBWWWWWWWWWWWWWWWWWWWWWWWWBWWWWWWWWWWWWWW";; 
12W1B12W3B24W1B14W 
val it : unit =() 
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"