2013-02-12 2 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

+0

네 말이 맞아. RLE가 무엇인지 기억하려면 잠시 기다려주십시오. – pad

답변

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 하나 개 더 인수로 시작하는 "부트 스트랩"축적이 필요합니다. 분명히 빈 목록 인 []이어야합니다.
참고 2 : x과 직접 일치시킬 수 없습니다. 대신 x0에 바인딩하고 x0x을 비교하십시오.
참고 3 : 빈 패턴리스트 []과 일치하는 것은 필요하지 않습니다. 마지막 패턴을 사용하면 행복 할 것입니다.

+2

그는'List.fold'에 두 번째 매개 변수를 잊어 버렸습니다. 당신은 아마 그것도 추가해야합니다. – pad

+2

최초의'map'도 필요 없습니다. 그리고이 접근법 (동의 함)을 사용하면 순서를 입력 목록의 순서와 일치 시키려면 결과 목록을 반대로해야합니다. – latkin

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"