2017-07-29 111 views
3

我想创建一个N×M乘法表程序,使用f#,其中n和m值由用户指定,并且表格计算并存储在二维数组中并显示在控制台上。格式乘法表f#输出

任何帮助将让我的阵列将显示在类似的格式来大加赞赏:

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

所有你要做的就是将其相乘之前加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#,但鉴于我们使用的是不具备功能的二维数组,我认为我可以偷偷摸摸了;)

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] 
+0

谢谢你,这是完美工作:)如何格式化表格有何建议? – NaNaNiii

5

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

的想法是这样的:

  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 

此功能容易遵循:如果字符串ALR超过最大限度,只需返回它,否则预先加上(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 
0

我无耻地复制的陀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 
" 
+1

列表理解功能完美,对他们没有任何要求。许多有抱负的程序员有这种倾向,将“功能”与“难以理解”混为一谈。不要堕入其中。 –

+0

@FyodorSoikin - 这就是为什么我把“功能”放在引号内。 – Soldalma