Вы можете переписать свой текущий подход как сворачивание, которое делает только один проход, как это:
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" ]))
]
]