patternMinor
Print diamond of any size
Viewed 0 times
diamondanyprintsize
Problem
I'm trying to print a diamond of asterisks of an arbitrary size. I'm new to F#, so I'm interested in virtually any feedback, but especially adherence to idioms, convention, and functional orientation.
module Diamond
open System
let rangeWithInverse (max) =
List.zip [ 1 .. max ] [ max .. -1 .. 1]
let listAscDesc (list) =
list @ (list |> List.rev |> List.skip 1)
let starsAndSpacesString (stars: int, spaces: int): string =
String.replicate spaces " " + String.replicate ((stars * 2) - 1) "*"
let diamond =
rangeWithInverse 18
|> listAscDesc
|> Seq.map starsAndSpacesString
|> Seq.reduce (fun a b -> a + "\n" + b)
[]
let main argv =
diamond |> printfn "%s"
0Solution
It's hard to comment on it. It seems OK to me - maybe a little to much list manipulation. I'm not sure if string concat with + is acceptable practice in F# but in general it's not. For fun I've tried with my own version with use of recursion:
Version with pattern match instead of if:
It's possible but does it add any good?
EDIT:
A condensed solution could be:
However none of the solutions are very performant if diamond size is increased (> 2000) due to the concatenation of strings. In that respect a good old iterative solution is preferable:
A gentle "refactoring" of BadHeuristics code:
let newDiamond n =
let rec print nn f =
if nn 0 then
let spaces = String.replicate ((n - nn) / 2) " "
sprintf "%s%s%s\n%s" spaces (String.replicate nn "*") spaces (print (f nn) f)
else
""
let add x = x + 2
let subt x = x - 2
let dn = if n % 2 = 0 then 3 else 2
sprintf "%s%s" (print 1 add) (print (n - dn) subt)
[]
let main argv =
newDiamond 36 |> printfn "%s"
Console.ReadLine() |> ignore
0Version with pattern match instead of if:
let newDiamond n =
let rec print nn f =
match nn with
| x when x = n + 1 -> ""
| _ -> let spaces = String.replicate ((n - nn) / 2) " "
sprintf "%s%s%s\n%s" spaces (String.replicate nn "*") spaces (print (f nn) f)
let add x = x + 2
let subt x = x - 2
let dn = if n % 2 = 0 then 3 else 2
sprintf "%s%s" (print 1 add) (print (n - dn) subt)It's possible but does it add any good?
EDIT:
A condensed solution could be:
let newDiamond n =
let topNs = [1..2..n]
let diamondNs = List.append topNs (topNs |> List.rev |> List.tail)
let createLine x =
sprintf "%s%s" (String.replicate ((n - x) / 2) " ") (String.replicate x "*")
(diamondNs |> Seq.mapFold (fun strs x -> ("", sprintf "%s\n%s" strs (createLine x))) "") |> sndHowever none of the solutions are very performant if diamond size is increased (> 2000) due to the concatenation of strings. In that respect a good old iterative solution is preferable:
let newDiamond n =
let createLine = (fun x -> sprintf "%s%s" (String.replicate ((n - x) / 2) " ") (String.replicate x "*"))
let topHalf = [ 1..2..n ]
let indices = topHalf @ (topHalf |> List.rev |> List.tail)
seq { for ln in indices do
yield createLine ln } |> Seq.iter (printfn "%s")A gentle "refactoring" of BadHeuristics code:
let rangeWithInverse max =
List.zip [ 1 .. max ] [ max .. -1 .. 1]
let listAscDesc list =
list @ (list |> List.rev |> List.tail) // tail instead of skip 1
let starsAndSpacesString (stars, spaces) =
sprintf "%s%s" (String.replicate spaces " ") (String.replicate ((stars * 2) - 1) "*") // sprintf instead of ""+""
let diamond n =
rangeWithInverse (n / 2)
|> listAscDesc
|> Seq.map starsAndSpacesString
|> Seq.reduce (fun a b -> sprintf "%s\n%s" a b) // sprintf instead of ""+""Code Snippets
let newDiamond n =
let rec print nn f =
if nn <= n && nn > 0 then
let spaces = String.replicate ((n - nn) / 2) " "
sprintf "%s%s%s\n%s" spaces (String.replicate nn "*") spaces (print (f nn) f)
else
""
let add x = x + 2
let subt x = x - 2
let dn = if n % 2 = 0 then 3 else 2
sprintf "%s%s" (print 1 add) (print (n - dn) subt)
[<EntryPoint>]
let main argv =
newDiamond 36 |> printfn "%s"
Console.ReadLine() |> ignore
0let newDiamond n =
let rec print nn f =
match nn with
| x when x <= 0 || x >= n + 1 -> ""
| _ -> let spaces = String.replicate ((n - nn) / 2) " "
sprintf "%s%s%s\n%s" spaces (String.replicate nn "*") spaces (print (f nn) f)
let add x = x + 2
let subt x = x - 2
let dn = if n % 2 = 0 then 3 else 2
sprintf "%s%s" (print 1 add) (print (n - dn) subt)let newDiamond n =
let topNs = [1..2..n]
let diamondNs = List.append topNs (topNs |> List.rev |> List.tail)
let createLine x =
sprintf "%s%s" (String.replicate ((n - x) / 2) " ") (String.replicate x "*")
(diamondNs |> Seq.mapFold (fun strs x -> ("", sprintf "%s\n%s" strs (createLine x))) "") |> sndlet newDiamond n =
let createLine = (fun x -> sprintf "%s%s" (String.replicate ((n - x) / 2) " ") (String.replicate x "*"))
let topHalf = [ 1..2..n ]
let indices = topHalf @ (topHalf |> List.rev |> List.tail)
seq { for ln in indices do
yield createLine ln } |> Seq.iter (printfn "%s")let rangeWithInverse max =
List.zip [ 1 .. max ] [ max .. -1 .. 1]
let listAscDesc list =
list @ (list |> List.rev |> List.tail) // tail instead of skip 1
let starsAndSpacesString (stars, spaces) =
sprintf "%s%s" (String.replicate spaces " ") (String.replicate ((stars * 2) - 1) "*") // sprintf instead of ""+""
let diamond n =
rangeWithInverse (n / 2)
|> listAscDesc
|> Seq.map starsAndSpacesString
|> Seq.reduce (fun a b -> sprintf "%s\n%s" a b) // sprintf instead of ""+""Context
StackExchange Code Review Q#145384, answer score: 3
Revisions (0)
No revisions yet.