f# - 格式化乘法表 f# 输出

标签 f# grid multiplication

我正在尝试使用 f# 创建一个 N x M 乘法表程序,其中 n 和 m 值由用户指定,并且该表被计算并存储在 2D 数组中并显示在控制台上。

如果我的数组以类似于以下的格式显示,我们将不胜感激:

Desired Output

与我程序中的那个相反

Current Output

我的源代码是

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)。

这个想法是这样的:

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

首先,让我们看看如何计算“单元格”的宽度。表中最宽的数字是多少?假设 nm 都是正数,那么最宽的数字显然是 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/

相关文章:

Python Tkinter 在 GUI 中嵌入 Matplotlib

python - 在 Python 2.6 中将回车符返回到 0,0

html - 网格元素未使用 minmax() 函数正确包装

java - 乘法口诀表格式问题

floating-point - 取对数并加或乘

generics - F# 泛型方法和运算符

f# - 在 F# 中,这些看起来像是集合的东西是什么?

performance - 检查计算的 F# 性能影响?

c# - 如何提取数字的位值?

f# - 确定列表的所有元素是否属于同一个 DU 案例