如何在Elm脚本中向表的所有列添加类

时间:2019-04-25 20:33:18

标签: elm

elm脚本从后端代码获取csv字符串csv。我要创建一个表,并且每个单元格的类名称应为列名称

可以从rows = String.split "\n" csv获得表的行。如果不需要定义类,可以通过在List.map上应用双重嵌套的rows来创建表。但是为了给每个单元格分配类,我需要保存row的第一个元素,该元素包含列(或类)名称,并将其与其余各行配对。由于榆木中没有for循环,因此我的策略是定义一个递归函数以创建所有tr元素,并使用tr连接List.map元素。此函数的输入是第一行names和另一行cols。它们都是List String。每次运行时,它使用两个列表的头(来自td)创建一个List.head,然后传递两个列表(来自List.drop)的其余元素进行递归。但是我无法连接两个返回的组件。

createRow names cols =
    case cols of
        [] -> text ""
        _ ->
            let
                c0 = (List.head cols)
                c = (List.drop 1 cols)
                n0 = (List.head names)
                n = (List.drop 1 names)
            in
                td [] [text <| toString <| c0]
                , createRow n c 

我应该在in块中放什么?还是有更好的方法实现我的目的?

2 个答案:

答案 0 :(得分:4)

首先,我建议您不要手动解析CSV。包管理器上有多个CSV解析器,因此我们可以专注于处理这些值。

https://package.elm-lang.org/packages/periodic/elm-csv/latest/Csv 是一个选项,但它们在解析后都会为您提供Csv类型,如下所示:

type alias Csv =
    { headers : List String
    , records : List (List String)
    }

正如您所触摸的,标题与每行中的值一样多(否则CSV无效)。通过递归进行删除/修饰可以完成工作,但是我们可以依靠列表操作来完成大部分工作,从而更具声明性:

classTable : Csv -> Html msg
classTable csv =
    table []
        (csv.records |> List.map (tableRow csv.headers))


tableRow : List String -> List String -> Html msg
tableRow headers values =
    let
        insertNextCellInRow ( header, value ) row =
            td [ class header ] [ text value ] :: row
    in
    tr []
        (List.map2 Tuple.pair headers values
            |> List.foldr insertNextCellInRow []
        )

注意:List.foldr是递归的,并以命令式语言达到循环的目的(“对于此列表中的每个项目,请应用此功能并在此其他列表中收集结果”)。但是,它与传递给它的值的类型无关,并且使我们能够专注于转换值。

答案 1 :(得分:3)

在递归函数中,您需要传递(部分计算的)结果,以便您可以在每次调用中对其进行修改,并在完成递归后将其返回。这样看起来可能像这样:

createRow : List String -> List String -> List (Html msg) -> List (Html msg)
createRow names cols cells =
    case cols of 
        [] -> cells
        col :: remainingCols ->
            let
                name = 
                    names
                    |> List.head
                    |> Maybe.withDefault ""
                remainingNames = List.drop 1 names
                cell =
                    td [class name] [text col]
            in
            createRow remainingNames remaningCols (cells ++ [ cell ])

此处还有其他一些值得注意的变化:

  • 我已经使用模式匹配从其余部分中提取了cols列表的开头(也称为结尾)
  • List.head返回一个Maybe a(在这种情况下,aString),所以我向Maybe.withDefault添加了一个呼叫
  • 由于colsList String,因此您无需调用toString,就可以直接将其传递给text
  • 首次调用此函数时,您将为[]参数传递cells