patternMinor
Printing a table
Viewed 0 times
printingtablestackoverflow
Problem
I have this recursive function that I made which prints a table, but I really think my current solution is really ugly. Does anyone have an idea as to how I can improve my solution?
I'm trying to implement without any variables and with the use of
I'm trying to implement without any variables and with the use of
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)Solution
Firstly,
So instead of this:
you could do this:
Secondly, all those
And your second line of
(although you could also use a list for clarity, especially if you want to make this useful for a varying number of columns)
Thirdly, this recursive function will never complete. Look at it closely: there is never a case where this function does not call itself. When
From your explanation ("print a table"), I conclude that what you really wanted is to first print the header (the constant string), and then under it print 6 rows of 10 numbers each. Right? If so, the base case should just return header, and each non-base case should construct its row and prepend previous result to it:
And fourthly, recursion is not really required for this task. True, you can encode any sequential process as a recursive function, but recursion is hard. It's tricky to get right (as this example illustrates), and even trickier to understand when reading the code. The usual approach to such problems is to encode the recursion once (in core library) as a parametrized function (for linear processes, such function is usually called
sprintf doesn't only take one argument, that wouldn't be very useful. It takes as many arguments (and of corresponding types) as are mentioned in the format string.So instead of this:
sprintf "%d" (n*1) + sprintf "\t%d" (n*2)you could do this:
sprintf "%d\t%d" (n*1) (n*2)Secondly, all those
sprintf calls look awfully similar to me. And when there is a repetition, there is usually a way to shorten it by parametrizing. Your first line of sprintfs could look something like this:let columns = [1..10] |> List.map ( (*) n ) |> String.concat "\t"
sprintf "\n%s" columnsAnd your second line of
sprintfs doesn't need any sprintfs at all - it's all constant!"\t1\t2\t3\t4\t5\t6\t7\t8\t9\t10"(although you could also use a list for clarity, especially if you want to make this useful for a varying number of columns)
Thirdly, this recursive function will never complete. Look at it closely: there is never a case where this function does not call itself. When
n=0, it will call itself with n=6, and when n>0, it will call itself with n=n-1. So that, once you call it, it will just keep calling itself indefinitely. Well, not completely indefinitely, but until it runs out of stack.From your explanation ("print a table"), I conclude that what you really wanted is to first print the header (the constant string), and then under it print 6 rows of 10 numbers each. Right? If so, the base case should just return header, and each non-base case should construct its row and prepend previous result to it:
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"And fourthly, recursion is not really required for this task. True, you can encode any sequential process as a recursive function, but recursion is hard. It's tricky to get right (as this example illustrates), and even trickier to understand when reading the code. The usual approach to such problems is to encode the recursion once (in core library) as a parametrized function (for linear processes, such function is usually called
fold), and then use this function, or its derivatives, in higher-level code. In your particular case, since you just want to produce a few strings and concatenate them, I would use 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)Code Snippets
sprintf "%d" (n*1) + sprintf "\t%d" (n*2)sprintf "%d\t%d" (n*1) (n*2)let columns = [1..10] |> List.map ( (*) n ) |> String.concat "\t"
sprintf "\n%s" columns"\t1\t2\t3\t4\t5\t6\t7\t8\t9\t10"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"Context
StackExchange Code Review Q#142542, answer score: 6
Revisions (0)
No revisions yet.