2

如何修改下面的代码以返回“字符串”,以便返回的输出显示在我的 MVC 页面上,并且还希望enteredChar从用户那里接受。

有没有更好的方法来创建这个金字塔?

当前代码:

let enteredChar = 'F' // As Interactive window doesn't support to Read Input
let mylist = ['A'..enteredChar] 
let mylistlength = mylist |> List.length
let myfunc i x tlist1 =
    (for j = 0 to mylistlength-i-2 do printf "%c" ' ')
    let a1 = [for p in tlist1  do if p < x then yield p]
    for p in a1 do printf "%c" p
    printf "%c" x
    let a2 = List.rev a1
    for p in a2 do printf "%c" p
    printfn "%s" " "

mylist |> List.iteri(fun i x -> myfunc i x mylist)

输出:

     A
    ABA
   ABCBA
  ABCDCBA
 ABCDEDCBA
ABCDEFEDCBA
4

5 回答 5

4

一些小的优化可能是:

  • 使用长字符串StringBuilder代替printfwhich 会很慢。
  • 使用Array代替ListsinceArray效果更好String

这是一个生成金字塔字符串的版本,它与您的代码密切相关:

open System
open System.Text

let generateString c = 
    let sb = StringBuilder()             
    let generate i x arr =
        String.replicate (Array.length arr-i-1) " " |> sb.Append |> ignore
        let a1 = Array.filter (fun p -> p < x) arr
        String(a1) |> sb.Append |> ignore
        sb.Append x |> ignore
        String(Array.rev a1) |> sb.Append |> ignore
        sb.AppendLine " " |> ignore

    let arr = [|'A'..c|]               
    arr |> Array.iteri(fun i x -> generate i x arr)
    sb.ToString()

generateString 'F' |> printfn "%s"
于 2012-07-06T15:51:55.360 回答
2

如果我理解您的问题(这可能属于Code Review),这是重写您的函数的一种方法:

let showPyramid (output: TextWriter) lastChar =
  let chars = [|'A' .. lastChar|]

  let getRowChars n = 
    let rec loop acc i =
      [|
        if i < n then let c = chars.[i] in yield c; yield! loop (c::acc) (i+1)
        else yield! List.tail acc
      |]
    loop [] 0

  let n = chars.Length
  for r = 1 to n do 
    output.WriteLine("{0}{1}{0}", String(' ', n - r), String(getRowChars r))

例子

showPyramid Console.Out 'F'

或者,输出到字符串

use output = new StringWriter()
showPyramid output 'F'
let pyramid = output.ToString()

编辑

看到 Tomas 的回答后,我意识到我在你的问题中跳过了“返回字符串”。我更新了代码并添加了示例来展示你如何做到这一点。

于 2012-07-06T15:39:20.567 回答
2

作为 Daniel 解决方案的替代方案,您只需对代码逻辑进行最少的更改即可实现您想要的。printf您可以使用whichPrintf.bprintf将输出写入指定的StringBuilder. 然后您可以简单地从StringBuilder.

修改后的函数将如下所示。我添加了参数str并替换printfPrintf.bprintf str(并printfnbprintf附加\n字符一起):

let myfunc i x tlist1 str = 
    (for j = 0 to mylistlength-i-2 do Printf.bprintf str "%c" ' ') 
    let a1 = [for p in tlist1  do if p < x then yield p] 
    for p in a1 do Printf.bprintf str "%c" p 
    Printf.bprintf str "%c" x 
    let a2 = List.rev a1 
    for p in a2 do Printf.bprintf str "%c" p 
    Printf.bprintf str "%s\n" " " 

要调用该函数,您首先要创建StringBuilder它,然后myfunc在每次调用中将其传递给它。最后,您可以使用ToString方法获得结果:

let str = StringBuilder()
mylist |> List.iteri(fun i x -> myfunc i x mylist str) 
str.ToString()

我认为 Daniel 的解决方案看起来更好,但这是将打印代码转换为字符串构建代码的最直接方法(几乎可以使用 Search & Replace 来完成)。

于 2012-07-06T15:46:14.527 回答
2
let pyramid (ch:char) = 
  let ar = [| 'A'..ch |]
  let len = ar.Length
  Array.mapi
    (fun i ch -> 
      let ar = ar.[0..i]
      String.replicate (len - i - 1) " " + new string(ar) + new string((Array.rev ar).[1..]))
    ar
  |> String.concat "\n" 

pyramid 'F' |> printfn "%s"
于 2012-07-07T01:53:28.973 回答
2

这是另一种方法,似乎很好地展示了功能组合。我敢打赌这是这里答案中最短的解决方案。:)

let charsToString = Seq.map string >> String.concat String.Empty
let pyramid lastChar =
    let src = '-'::['A'..lastChar] |> List.toArray
    let len = Array.length src - 1

    fun row col -> row-abs(col-len+1)+1 |> max 0 |> Array.get src   // (1)
    >> Seq.init (len*2-1) >> charsToString                          // (2)
    |> Seq.init len                                                 // (3)

pyramid 'X' |> Seq.iter (printfn "%s")
  • 首先,我们生成一个不寻常的初始数据数组。它的元素[0]包含一个空格或任何你想要的分隔符;我更喜欢用破折号 ( -) 进行调试。
  • (1)行创建了一个函数来计算要放置的字符。的结果row-abs(col-len+1)+1可以是正数(并且要放置一个字符)或zeronegative,并且应该有一个空格。注意没有if 声明:隐藏在max函数内部;
  • (2)行构成一个int -> string用于生成单个行的函数;
  • (3)行将上面的函数作为序列初始化器的参数传递。

这三行可以写成更详细的方式:

    let genCell row col = row-abs(col-len+1)+1 |> max 0 |> Array.get src 
    let genRow = genCell >> Seq.init (len*2-1) >> charsToString
    Seq.init len genRow

由于函数组合,注意genRow不需要正式的参数:参数被绑定到genCell,返回单个参数的函数,正是Seq.init需要的。

于 2012-07-07T14:27:32.680 回答