F# 开发一个函数,该函数接受一个整数列表,该列表定义了最长的连续相同数链
请帮忙 开发一个函数,该函数接受一个整数列表,该列表定义了最长的连续相同数链。函数的结果必须是一对(数字、链的长度) 我的代码:-F# 开发一个函数,该函数接受一个整数列表,该列表定义了最长的连续相同数链,f#,functional-programming,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)) |
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”后面的块未完成。期待一个表情
这可能是问题所在吗?按如下格式进行编译:
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
既然你的主要问题已经得到了回答,这里还有另一个选择/方法,为了乐趣和利润:)
正如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
- 我还将
拆分为多行(为了可读性-这不是必需的)
List.fold
的版本,我想我应该用您原始代码的更正版本来回答
另一方面,如果您想对一些实际数据(如时间序列)执行更多类似这样的操作,而不是为了学习F#而解决这个问题,那么这是一个用于处理序列数据的库,它有一个很好的抽象,称为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]
抱歉,但迄今为止我见过的大多数F#代码在我看来都像是伪装的C。我相信函数式F#程序员可以做得更好,按照Haskell的解决方案:
maxrv = maximumBy (comparing fst) . map (\xs -> (length xs, xs)) . group
这里有一个尝试,它是通用的,并且使用标准的库函数。由于您没有说明当输入序列为空时答案应该是什么,所以我不会直接返回一对
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
让内联findMaxSeq xs=
xs
|>序列扫描(乐趣状态x->
匹配状态
|当x=y时的一些(y,i)->一些(x,i+1)
|一些(x,1))
没有一个
|>Seq.maxBy(函数
|一些(u,i)->i
| _ -> 0 )
findMaxSeq[1;2;2;3;3;1;1;1;1;1;4;4]//一些(1,5)
findMaxSeq Seq.empty//None
-1很好的一点,但很抱歉,这可以作为一个注释吗?F#没有Haskell那样的组
功能,但一旦你编写了一个,你就可以产生一个几乎与你自己的解决方案完全一样的解决方案()@Daniel似乎是系列。chunkWhile
是类似的,请参见@Thomas Petricek.Yep.的答案。看起来很相似。这是他写的一个名为Deedle的图书馆。
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