Как разделить список на четыре списка в вязе? - PullRequest
5 голосов
/ 05 июля 2019

У меня есть список предметов, которые нужно визуализировать. У меня есть функция с именем 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
                ]
            ]
        ]

Ответы [ 2 ]

5 голосов
/ 05 июля 2019

Вы можете переписать свой текущий подход как сворачивание, которое делает только один проход, как это:

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

Это также отслеживает индекс внутри, поэтому не требует, чтобы вы дали ему индексированныйсписок, но он все еще жестко запрограммирован для четырех столбцов.Если мы хотим иметь возможность использовать его с произвольным числом столбцов, мы должны использовать структуру данных, которая может содержать произвольное количество элементов в последовательности.Массив идеально подходит для этого, позволяя нам обновлять его индексом, вычисленным с использованием 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" ]))
            ]
        ]
4 голосов
/ 05 июля 2019

Вы можете использовать List.map с List.range.List.range a b генерирует список целых чисел от a до b (включительно).

Ваша 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)
            ]
        ]

Если вы хотитеПоддерживая другое количество столбцов, вы, конечно, можете заменить жестко закодированный 4 в splitColumns параметром.

...