Ana*_*nth 5 functional-programming 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
]
]
]
Run Code Online (Sandbox Code Playgroud)
您可以List.map与 一起使用List.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)
]
]
Run Code Online (Sandbox Code Playgroud)
如果你想支持不同数量的列,你当然可以用参数替换硬4编码。splitColumns
您可以将当前方法重写为仅一次通过这样的折叠:
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
Run Code Online (Sandbox Code Playgroud)
这也可以在内部跟踪索引,因此不需要您为其提供索引列表,但是仍然为四列进行了硬编码。如果我们希望能够将其与任意数量的列一起使用,则必须使用可以按顺序容纳任意数量的项目的数据结构。数组非常适合此操作,允许我们使用使用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
Run Code Online (Sandbox Code Playgroud)
然后List.map,我们可以在view函数中使用它们来渲染它们:
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" ]))
]
]
Run Code Online (Sandbox Code Playgroud)