格式化乘法表f#输出

NaN*_*iii 3 grid f# multiplication

我正在尝试使用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()
Run Code Online (Sandbox Code Playgroud)

此外,我想知道如何让我的值从1开始而不是0.

任何帮助都会非常感激,因为我是F#的初学者.

Fyo*_*kin 5

与任何UI任务一样,格式化输出通常会变得非常棘手.这种情况也不例外.

这个想法是这样的:

  1. 弄清楚表格的"单元格"应该有多宽.
  2. 通过将转换为字符串并填充到单元格宽度的数字连接在一起来构建每一行.
  3. 前置第一行.
  4. 连接用换行符分隔它们的所有行.

首先,让我们看看我们如何计算出"细胞"的宽度.表中最宽的数字是多少?假设这两个nm是积极的,最宽的数量会n*m很明显.所以,我们可以像这样计算单元格的宽度:

let cellWidth = (n*m) |> string |> String.length
Run Code Online (Sandbox Code Playgroud)

同样,第一个(最左边)列将与其中的最大数字一样宽,即n:

let firstColWidth = n |> string |> String.length
Run Code Online (Sandbox Code Playgroud)

现在,让我们自己创建一个函数,它将带一个数字并用空格填充所需的宽度:

let pad totalWidth (value: obj) = 
    let s = string value
    if s.Length >= totalWidth then s
    else (String.replicate (totalWidth-s.Length) " ") + s
Run Code Online (Sandbox Code Playgroud)

这个函数很容易理解:如果字符串已经超过最大值,只需返回它,否则(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
Run Code Online (Sandbox Code Playgroud)

同样,格式化最顶行:

let firstRow = 
    let cols = [for col in 1..m -> col |> pad cellWidth]
    let firstCol = " " |> pad firstColWidth
    let wholeRow = firstCol :: cols
    String.concat " " wholeRow
Run Code Online (Sandbox Code Playgroud)

看看这些功能有多相似:唯一的区别是grid.[rowIdx,colIdx]vs 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)
Run Code Online (Sandbox Code Playgroud)

最后,格式化每一行,先添加第一行,然后将它们连接在一起:

let rows = [0..n-1] |> List.map formatRow
let allRows = firstRow :: rows
String.concat "\n" allRows
Run Code Online (Sandbox Code Playgroud)

最终代码:

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
Run Code Online (Sandbox Code Playgroud)