我有一个递归函数,它打印了一个表,但是我真的认为我目前的解决方案很难看。有人知道我如何改进我的解决方案吗?
我试图在没有任何变量的情况下使用sprintf
来实现。
let rec rec n =
if n > 0 then
rec(n-1) + sprintf "\n"+sprintf "%d" (n*1) + sprintf "\t%d" (n*1)+ sprintf "\t%d" (n*2) + sprintf "\t%d" (n*3) + sprintf "\t%d" (n*4)
+ sprintf "\t%d" (n*5) + sprintf "\t%d" (n*6) + sprintf "\t%d" (n*7) + sprintf "\t%d" (n*8) + sprintf "\t%d" (n*9) + sprintf "\t%d" (n*10)
else
sprintf "\t%d" 1 + sprintf "\t%d" 2 + sprintf "\t%d" 3 + sprintf "\t%d" 4 + sprintf "\t%d" 5 + sprintf "\t%d" 6 + sprintf "\t%d" 7 + sprintf "\t%d" 8 + sprintf "\t%d" 9 + sprintf "\t%d" 10
printfn "%s" (rec 6)
发布于 2016-09-26 19:15:32
首先,sprintf
不只是采取一个论点,这将不是很有用的。它所使用的参数(以及相应类型)与格式字符串中提到的一样多。
所以,不是这样的:
sprintf "%d" (n*1) + sprintf "\t%d" (n*2)
你可以这样做:
sprintf "%d\t%d" (n*1) (n*2)
其次,所有这些sprintf
调用看起来都与我非常相似。当有重复的时候,通常会有一种方法通过参数化来缩短它。您的sprintf
s的第一行可能是这样的:
let columns = [1..10] |> List.map ( (*) n ) |> String.concat "\t"
sprintf "\n%s" columns
你的第二行sprintf
s根本不需要任何sprintf
s
"\t1\t2\t3\t4\t5\t6\t7\t8\t9\t10"
(尽管您也可以使用一个列表来表示清楚,特别是如果您希望使它对不同数量的列有用)
第三,这个递归函数永远不会完成。仔细看一看:从来没有这个函数不调用自己的情况。当n=0
的时候,它会用n=6
来称呼自己,当n>0
时,它会用n=n-1
来称呼自己。所以,一旦你称之为它,它就会无限期地自我标榜。嗯,不完全是无限期的,但是直到它用完为止。
根据您的解释(“打印一个表”),我得出的结论是,您真正想要的是首先打印标题(常量字符串),然后在它下面打印6行,每行10个数字。对吗?如果是这样的话,基本大小写应该只返回标头,每个非基本大小写都应该构造它的行并将先前的结果加到它的前面:
let row n =
[1..10]
|> List.map ( (*) n )
|> String.concat "\t"
|> sprintf "\n%s"
let rec table n =
if n > 0 then table (n-1) + row n
else "\t1\t2\t3\t4\t5\t6\t7\t8\t9\t10"
第四,这一任务并不真正需要递归。是的,您可以将任何顺序进程编码为递归函数,但递归很难实现。要正确理解(如本例所示)是很棘手的,在阅读代码时更难理解。解决此类问题的通常方法是将递归(在核心库中)编码一次,作为参数化函数(对于线性过程,这类函数通常称为fold
),然后在更高级别的代码中使用该函数或其导数。在您的特殊情况下,由于您只想生成几个字符串并将它们连接起来,所以我将使用map
:
let row n =
[1..10]
|> List.map ( (*) n )
|> String.concat "\t"
|> sprintf "\n%s"
let table n =
let header = "\t1\t2\t3\t4\t5\t6\t7\t8\t9\t10"
let rows = [1..n] |> List.map row
sprintf "%s\n%s" header (String.concat "\n" rows)
发布于 2016-09-27 07:40:12
递归解决方案可以是:
let print rows cols =
let listRow row = ([1 .. cols] |> List.fold (fun str n -> sprintf "%s\t%d" str (n * row)) "")
let head = listRow 1
let rec doRow row =
if row <= rows then
let curline = sprintf "%d%s" row (listRow row)
let nextlines = doRow (row + 1)
sprintf "%s\n%s" curline nextlines
else
""
sprintf "%s\n%s" head (doRow 1)
[<EntryPoint>]
let main argv =
printfn "%s" (print 6 10)
Console.ReadLine()|>ignore
0
以及一个基于清单的版本:
let print rows cols =
let listRow row =
[1 .. cols]
|> List.map (fun n -> sprintf "%d" (n * row))
|> String.concat "\t"
let header = sprintf "\t%s" (listRow 1)
let table =
[1 .. rows]
|> List.map (fun n -> sprintf "%d\t%s" n (listRow n))
|> String.concat "\n"
sprintf "%s\n%s" header table
https://codereview.stackexchange.com/questions/142542
复制相似问题