代码之家  ›  专栏  ›  技术社区  ›  dharmatech

格式表的等效项

f#
  •  0
  • dharmatech  · 技术社区  · 3 年前

    PowerShell中的表格格式

    在PowerShell中,如果我有一个对象列表:

    $items = @(
        [pscustomobject]@{ a = 10;   b = 20;    c = "bcd" }
        [pscustomobject]@{ a = 300;  b = 400;   c = "bcde" }
        [pscustomobject]@{ a = 5000; b = 60000; c = "bcdef" }
    ) 
    

    我可以将对象显示为表格:

    $items | Format-Table
    

    结果:

       a     b c
       -     - -
      10    20 bcd
     300   400 bcde
    5000 60000 bcdef
    

    F#

    如果我在F#中有类似的列表:

    type Abc = {
        a : int
        b : int
        c : string
    }
    
    let items = [
        { a = 10; b = 20; c = "bcd" }
        { a = 300; b = 400; c = "bcde" }
        { a = 5000; b = 60000; c = "bcdef" }
    ] 
    

    如果我想显示类似的表格,我必须更加明确:

    items |> List.iter (fun item -> printfn "%10d %10d %s" item.a item.b item.c) 
    

    format_table函数

    这是一个 format_table 函数(使用 Fli ):

    let format_table seq =
        let json = JsonSerializer.Serialize seq
        System.IO.File.WriteAllText("c:/temp/out.json", json)
        let result_cli = (cli {
            Shell PS
            Command "Get-Content c:\\temp\\out.json | ConvertFrom-Json | Format-Table"
        } |> Command.execute)
    
        match result_cli.Text with
        | Some(txt) -> printfn "%s" txt
        | None -> printfn "issue"
    

    所以我可以做到:

    items |> format_table
    

    并获得:

    a b c
    ---
    10 20 bcd
    300 400 bcde
    5000 60000 bcdef
    

    问题

    正如你所看到的, format_table 是一个很好的解决方法:

    • 它将列表序列化为JSON
    • 它将JSON写入一个临时文件
    • 它执行PowerShell,PowerShell使用 Format-Table 关于数据

    有没有一种简单的方法来写类似于 format_table 而不依赖于外部PowerShell进程?

    1 回复  |  直到 3 年前
        1
  •  1
  •   Martin521    3 年前

    这是一个简单的版本,使用反射。

    open System.Reflection
    open FSharp.Reflection
    
    let printTable items =
        let genArgs = items.GetType().GenericTypeArguments
        assert (genArgs.Length = 1)
        let itemType = genArgs[0]
        assert (FSharpType.IsRecord itemType)
        let fieldNames = FSharpType.GetRecordFields itemType |> Array.map (fun propInfo -> propInfo.Name)
        printfn $"""{fieldNames |> Array.map (sprintf "%10s") |> String.concat ""}"""
        printfn $""" {Array.replicate fieldNames.Length "_________" |> String.concat " "}"""
        let printFields item =
            let fields =  FSharpValue.GetRecordFields item
            printfn $"""{fields |> Array.map (string >> sprintf "%10s") |> String.concat ""}"""
        items |> Seq.iter printFields