格式化乘法表f#output

时间:2017-07-29 19:03:13

标签: 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#的初学者。

3 个答案:

答案 0 :(得分:5)

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

这个想法是这样的:

  1. 弄清楚桌子的“单元格”应该有多宽。
  2. 通过将转换为字符串并填充到单元格宽度的数字连接在一起来构建每一行。
  3. 前置第一行。
  4. 连接用换行符分隔它们的所有行。
  5. 首先,让我们看看我们如何计算出“细胞”的宽度。表中最宽的数字是多少?假设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
    

答案 1 :(得分:3)

你需要做的就是在将它们相乘之前加1到n和m,例如

let multiplication  n m = Array2D.init n m (fun n m -> (n + 1) * (m + 1))

但是我们在这里确实有一些括号疯狂,你可以将其重构为:

let myMultFunction n m = (n + 1) * (m + 1)
let multiplication n m = Array2D.init n m myMultFunction

格式化会有点棘手,使用for循环有点作弊,而不是非常F#,但鉴于我们使用的是2d数组,这些数组本质上不起作用,我想我可以偷偷摸摸;)

printfn "A multiplication table:"
printf "   "
for col in 0 .. mValue - 1 do
    printf "%d\t" (col + 1)

printfn ""
for row in 0 .. nValue - 1 do
    for col in 0 .. mValue - 1 do
            if col = 0 then
                    printf "\n%d| " (row + 1)
            printf "%d\t" grid.[row, col]

答案 2 :(得分:0)

我无耻地复制了Fyodor Soikin的一些优秀答案,但更改了剩下的部分以使代码更多"功能性"对于那些具有“必要性”的人来说,虽然不那么明确。弯曲。

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

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 frow str (rw: int []) = (Array.fold (fun s i -> s + (pad cellWidth i)) str rw) + "\n"
    let firstRow = frow ("\n" + pad (firstColWidth+2) "") [|1..m|]
    let folder str i = str + (frow ((pad firstColWidth (i+1)) + "| ") grid.[i, 0..])

    List.fold folder firstRow [0..(n-1)]

let a2d = array2D [[1;2;3]; [4;5;6]]
formatGrid a2d

输出结果为:

val it : string = "
   123
1| 123
2| 456
"