如何修改下面的代码以返回“string”,以便返回的输出显示在我的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
答案 0 :(得分:4)
一些小的优化可能是:
StringBuilder
代替printf
,这对于长字符串而言非常慢。Array
代替List
,因为Array
可以更好地与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"
答案 1 :(得分: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的回答后,我意识到我在你的问题中跳过了“返回一个字符串”。我更新了代码并添加了一些示例来说明如何做到这一点。
答案 2 :(得分:2)
作为Daniel解决方案的替代方案,您可以通过对代码逻辑的最小更改来实现您的目标。您可以使用printf
将输出写入指定的Printf.bprintf
,而不是使用StringBuilder
将输出写入控制台。然后,您只需从StringBuilder
获取结果字符串。
修改后的功能如下所示。我添加了参数str
,并将printf
替换为Printf.bprintf str
(printfn
替换为bprintf
以及其他\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&amp; Replace来完成它。)
答案 3 :(得分: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"
答案 4 :(得分: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]
包含一个空格或你想拥有的任何分隔符;我首选dash(-
)用于调试目的。(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
所需要的。