如何在 elm 中将一个列表分成四个列表?

How do I split a list in to four lists in elm?

我有一个必须呈现的项目列表。我有一个名为 viewItem 的函数,它可以呈现一个项目。我做了一个简单的 List.map viewItem items,现在我有了一个可以显示的项目列表。

我的视图有四列。如何将此列表拆分为包含原始列表中所有元素的四个列表?

这就是我现在的做法,但一定有我遗漏的地方。我希望能够将它分成五列甚至六列,而不必每次都写 col4 = ...col5 = ...

splitColumns : Int -> Array a -> Array (List a)
splitColumns cnum xs =
    let
        ixdList =
            Array.toIndexedList xs
    in
    List.filterMap
        (\a ->
            if modBy 4 (Tuple.first a) == cnum then
                Just (Tuple.second a)

            else
                Nothing
        )
        ixdList


viewItems : Array Item -> Html msg
viewItems items =
    let
        itemsHtml =
            Array.map viewItem items

        col0 =
            splitColumns 0 itemsHtml

        col1 =
            splitColumns 1 itemsHtml

        col2 =
            splitColumns 2 itemsHtml

        col3 =
            splitColumns 3 itemsHtml
    in
    main_
        [ class "section" ]
        [ Html.div
            [ class "container" ]
            [ Html.div
                [ class "columns" ]
                [ Html.div
                    [ class "column" ]
                    col0
                , Html.div
                    [ class "column" ]
                    col1
                , Html.div
                    [ class "column" ]
                    col2
                , Html.div
                    [ class "column" ]
                    col3
                ]
            ]
        ]

您可以将 List.mapList.range 一起使用。 List.range a b 生成从 ab(含)的整数列表。

你的 viewItems 功能因此大大简化:

viewItems : Array Item -> Html msg
viewItems items =
    main_
        [ class "section" ]
        [ Html.div
            [ class "container" ]
            [ Html.div
                [ class "columns" ]
                List.map (\n -> Html.div [ class "column" ] (splitColumns n (Array.map viewItem items)) (List.range 0 3)
            ]
        ]

如果你想支持不同的列数,当然可以把splitColumns中的hard-coded4换成一个参数

您可以将您当前的方法重写为只进行一次的折叠,如下所示:

cols : List a -> { col0 : List a, col1 : List a, col2 : List a, col3 : List a }
cols list =
    list
        |> List.foldl
            (\x ( i, cols ) ->
                case modBy 4 i of
                    0 ->
                        ( i + 1, { cols | col0 = x :: cols.col0 } )

                    1 ->
                        ( i + 1, { cols | col1 = x :: cols.col1 } )

                    2 ->
                        ( i + 1, { cols | col2 = x :: cols.col2 } )

                    3 ->
                        ( i + 1, { cols | col3 = x :: cols.col3 } )

                    _ ->
                        ( i + 1, cols )
            )
            ( 0, { col0 = [], col1 = [], col2 = [], col3 = [] } )
        |> Tuple.second

这也在内部跟踪索引,因此不需要您为其提供索引列表,但它仍然是 hard-coded 四列。如果我们希望能够将它用于任意数量的列,我们必须使用可以按顺序容纳任意数量项目的数据结构。数组非常适合这个,允许我们使用使用 modBy:

计算的索引更新它
cols : Int -> List a -> List (List a)
cols n list =
    list
        |> List.foldl
            (\x ( i, cols ) ->
                let
                    index =
                        modBy n i

                    tail =
                        cols |> Array.get index |> Maybe.withDefault []
                in
                ( i + 1, Array.set index (x :: tail) cols )
            )
            ( 0, Array.repeat n [] )
        |> Tuple.second
        |> Array.toList

然后我们可以在视图函数中使用List.map来渲染它们:

viewItems : Array Item -> Html msg
viewItems items =
    let
        itemsHtml =
            Array.map viewItem items
                |> Array.toList
    in
    main_
        [ class "section" ]
        [ Html.div
            [ class "container" ]
            [ Html.div
                [ class "columns" ]
                (cols 4 itemsHtml |> List.map (Html.div [ class "column" ]))
            ]
        ]