我正在尝试使用 f# 创建一个 N x M 乘法表程序,其中 n 和 m 值由用户指定,并且该表被计算并存储在 2D 数组中并显示在控制台上。
如果我的数组以类似于以下的格式显示,我们将不胜感激:
与我程序中的那个相反
我的源代码是
open System
let func() =
let multiplication n m = Array2D.init n m (fun n m -> n * m)
printf "Enter N Value: "
let nValue = Console.ReadLine() |> System.Int32.Parse
printf "\nEnter M Value: "
let mValue = Console.ReadLine() |> System.Int32.Parse
let grid = multiplication nValue mValue
printfn "\n\n%A" grid
func()
我还想知道如何让我的值从 1 开始,而不是 0。
任何帮助将不胜感激,因为我是 F# 的初学者。
最佳答案
与任何 UI 任务一样,格式化输出通常会非常棘手。本案也不异常(exception)。
这个想法是这样的:
- 弄清楚表格的“单元格”应该有多宽。
- 通过将转换为字符串并填充到单元格宽度的数字连接在一起来构建每一行。
- 添加第一行。
- 用换行符连接所有分隔它们的行。
首先,让我们看看如何计算“单元格”的宽度。表中最宽的数字是多少?假设 n
和 m
都是正数,那么最宽的数字显然是 n*m
。所以,我们可以这样计算单元格的宽度:
let cellWidth = (n*m) |> string |> String.length
同样,第一列(最左边)的宽度与其中最大的数字一样宽,即 n
:
let firstColWidth = n |> string |> String.length
现在,让我们自己创建一个函数,它会接受一个数字并用空格将其左填充到所需的宽度:
let pad totalWidth (value: obj) =
let s = string value
if s.Length >= totalWidth then s
else (String.replicate (totalWidth-s.Length) " ") + s
这个函数很容易理解:如果字符串已经超过最大值,则直接返回,否则在其前面加上 (totalWidth-s.Length)
个空格。
有了这个函数,我们可以格式化一行网格:
let formatRow rowIdx =
let cells = [for colIdx in 0..m-1 -> grid.[rowIdx,colIdx] |> pad cellWidth] // Each cell in this row padded to `cellWidth`
let firstCol = (rowIdx+1) |> pad firstColWidth // Leftmost column - just the row index itself padded to `firstColWidth`
let wholeRow = firstCol :: cells // Whole row consists of the leftmost column plus subsequent cells
String.concat " " wholeRow
同样,格式化最上面一行:
let firstRow =
let cols = [for col in 1..m -> col |> pad cellWidth]
let firstCol = " " |> pad firstColWidth
let wholeRow = firstCol :: cols
String.concat " " wholeRow
看看这些函数有多相似:唯一的区别是 grid.[rowIdx,colIdx]
与 col
。我们为什么不把它概括一下?
let formatRowWith firstCell getCell =
let cells = [for colIdx in 0..m-1 -> getCell colIdx |> pad cellWidth]
let firstCol = firstCell |> pad firstColWidth
let wholeRow = firstCol :: cells
String.concat " " wholeRow
let formatRow rowIdx = formatRowWith (rowIdx+1) (fun c -> grid.[rowIdx,c])
let firstRow = formatRowWith " " (fun c -> c+1)
最后,格式化每一行,将第一行放在前面,然后将它们连接在一起:
let rows = [0..n-1] |> List.map formatRow
let allRows = firstRow :: rows
String.concat "\n" allRows
最终代码:
let formatGrid (grid:_[,]) =
let n, m = grid.GetLength 0, grid.GetLength 1
let cellWidth = (n*m) |> string |> String.length
let firstColWidth = n |> string |> String.length
let pad totalWidth (value: obj) =
let s = string value
if s.Length >= totalWidth then s
else (String.replicate (totalWidth-s.Length) " ") + s
let formatRowWith firstCell getCell =
let cells = [for colIdx in 0..m-1 -> getCell colIdx |> pad cellWidth]
let firstCol = firstCell |> pad firstColWidth
let wholeRow = firstCol :: cells
String.concat " " wholeRow
let formatRow rowIdx = formatRowWith (rowIdx+1) (fun c -> grid.[rowIdx,c])
let firstRow = formatRowWith " " id
let rows = [0..n-1] |> List.map formatRow
let allRows = firstRow :: rows
String.concat "\n" allRows
关于f# - 格式化乘法表 f# 输出,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45393006/