开发一个函数,该函数采用整数列表,将整数列表定义为最长的相同数字的连续链

时间:2014-02-05 16:40:07

标签: f# functional-programming

请帮忙。

开发一个函数,该函数采用整数列表,将整数列表定义为相同数字的最长连续链。函数的结果必须是一对(数字,链的长度)

我的代码: -

let findMaxSeq (nums: int list) = 
let foldFun (curN, len, (curWinN, curWinLen)) n = 
match len, curWinLen with 
| 0, 0 -> (n, 1, (n,1)) 
| 0, _ -> (n, 1, (curWinN,curWinLen)) 
| _ when n = curN -> 
let newLen = len+1 
if (newLen>curWinLen) then (n, newLen, (n, newLen)) else (n, newLen, (curWinN, curWinLen))
| _ -> (n, 1, (curWinN, curWinLen))

let (_, _, (winner)) = nums |> List.fold foldFun (0, 0, (0, 0))
winner

但不编译 - 在第二个让我有错误: -

  

阻止此'let'未完成。期待一个表达。

5 个答案:

答案 0 :(得分:3)

缩进是不是问题?它按以下格式编译:

let findMaxSeq (nums: int list) = 
  let foldFun (curN, len, (curWinN, curWinLen)) n = 
    match len, curWinLen with 
    | 0, 0 -> (n, 1, (n,1)) 
    | 0, _ -> (n, 1, (curWinN,curWinLen)) 
    | _ when n = curN -> 
      let newLen = len+1 
      if (newLen>curWinLen) then (n, newLen, (n, newLen)) 
      else (n, newLen, (curWinN, curWinLen))
    | _ -> (n, 1, (curWinN, curWinLen))
  let (_, _, (winner)) = nums |> List.fold foldFun (0, 0, (0, 0))
  winner

这看起来像是一个有趣的挑战,所以我抓了它。

let findMaxRepeatedValue xs = 
  let rec loop (maxVal, maxCount) (curVal, curCount) = function
  | [] -> if curCount > maxCount then (curVal, curCount) else (maxVal, maxCount)
  | x::xs when x = curVal -> loop (maxVal, maxCount) (curVal, curCount + 1) xs
  | x::xs -> 
    if curCount > maxCount then loop (curVal, curCount) (x, 1) xs
    else loop (maxVal, maxCount) (x, 1) xs
  match xs with
  | [] -> invalidArg "xs" "empty list"
  | [x] -> (x, 1)
  | x::xs -> loop (x, 1) (x, 1) xs

答案 1 :(得分:3)

由于您的主要问题已得到解答,这里是另一种选择/方法,以获得乐趣和利润:)

let longestChain nums =
    let rec chain lst (num, cnt) = seq {
        match lst with
        | x :: xs -> if x = num then 
                        yield! chain xs (num, cnt+1) 
                     else 
                        yield (num, cnt) 
                        yield! chain xs (x, 1)
        | [] -> yield (num, cnt)
    }
    match nums with
    | x :: xs -> chain xs (x, 1) |> Seq.maxBy snd
    | [] -> failwith "Cannot find the longest chain in an empty list"

答案 2 :(得分:2)

正如Daniel指出的那样,这只是一个缩进问题 - F#是一种缩进敏感语言(空格有意义),所以你需要进一步缩进嵌套块。正确缩进后,您的功能正常工作!

let findMaxSeq (nums: int list) = 
  let foldFun (curN, len, (curWinN, curWinLen)) n = 
    match len, curWinLen with 
    | 0, 0 -> (n, 1, (n,1)) 
    | 0, _ -> (n, 1, (curWinN,curWinLen)) 
    | _ when n = curN -> 
       let newLen = len+1 
       if (newLen>curWinLen) then 
         (n, newLen, (n, newLen)) 
       else 
         (n, newLen, (curWinN, curWinLen))
    | _ -> (n, 1, (curWinN, curWinLen))

  let (_, _, (winner)) = nums |> List.fold foldFun (0, 0, (0, 0))
  winner

findMaxSeq [1;2;2;2;3;3;1;1;1;1;1;4;4]

请注意:

  • 函数foldFun的主体比定义函数的let缩进得更多。
  • 复杂模式的主体(当n=curN时匹配)也进一步缩进
  • 我还将if then拆分为多行(为了便于阅读 - 这不是必需的)

Daniel的解决方案也非常好 - 但是由于您询问了基于List.fold的版本,我想我会回复您原始代码的更正版本。

顺便说一句,如果你想在一些实际数据(如时间序列)上做更多这样的操作,而不是仅仅为了学习F#而解决这个问题,那么Deedle这是一个用于处理的库系列数据有一个很好的抽象,称为chunkWhile,它将系列分成块,而某些条件保持不变(例如,当值相同时)并且很容易编写它:

#r "lib/Deedle.dll"
open Deedle

let findMaxSeq values = 
  let s = Series.ofValues values
  s |> Series.chunkWhile (fun k1 k2 -> s.[k1] = s.[k2])
    |> Series.map(fun k chunk -> s.[k], Series.countKeys chunk)
    |> Series.values
    |> Seq.maxBy snd

findMaxSeq [1;2;2;2;3;3;1;1;1;1;1;4;4]

答案 3 :(得分:1)

这是一种通用的尝试并使用标准库函数。由于当输入序列为空时你没有说出答案应该是什么,我不是直接返回一对number * length,而是将它包装在一个选项中。

let inline findMaxSeq xs =
    xs 
    |> Seq.scan (fun state x ->
        match state with
        | Some (y, i) when x = y -> Some (x, i + 1)
        | _ -> Some (x, 1) )
        None
    |> Seq.maxBy (function
        | Some (_, i) -> i 
        | _ -> 0 )

findMaxSeq [1;2;2;2;3;3;1;1;1;1;1;4;4] // Some (1, 5)
findMaxSeq Seq.empty<int>              // None

答案 4 :(得分:-2)

很抱歉,但到目前为止,我见过她的大多数F#代码看起来都像C#一样伪装。我确信功能 F#程序员可以按照这个Haskell解决方案做得更好:

maxrv = maximumBy (comparing fst) . map (\xs -> (length xs, xs)) . group