我想在我的Elm程序中组合两个数据结构。他们的类型是Syndication_publication = 1
和List (a, List b)
。这是在模型中存储数据的最简单方法,但我想在显示之前编写一个函数将其转换为视图模型。
List c
type alias Model1 a b = List (a, List b)
type alias Model2 c = List c
type alias ViewModel a b c = List (a, List (b, c))
toViewModel : Model1 -> Model2 -> ViewModel
toViewModel model1 model2 =
???
函数应该使用模型2的元素压缩模型1中的子列表。假设model2的大小与模型1中子列表的大小总和相同。 / p>
例如,如果model1的长度为2且两个元素的子列表的长度为3和4,则假设模型2的长度为7.模型1的第一个元素的子列表应使用模型2的前3个元素进行压缩,并且模型1的第二个元素的子列表应该用模型2的接下来的4个元素压缩。
这是上一个例子的图表:
如何构建toViewModel
函数?
答案 0 :(得分:3)
Elm没有内置的zip
功能,但很容易根据List.map2
来定义它:
zip : List a -> List b -> List (a, b)
zip = List.map2 (,)
您不能单独在脱节列表中使用它,但您可以使用它来使用Model2中的第一个n
项来压缩Model1中的子列表。要获取需要压缩的内容列表,您只需要使用List.take
作为压缩部分,List.drop
来获取需要压缩的Model2中的其余项目使用下一个Model1实体。这可以使用类似下面的函数来完成。
toViewModel : Model1 a b -> Model2 c -> ViewModel a b c
toViewModel m1 m2 =
case m1 of
[] ->
[]
((m1ID, m1List)::rest) ->
let
len = List.length m1List
init' = List.take len m2
tail' = List.drop len m2
in
(m1ID, zip m1List init') :: toViewModel rest tail'
请注意,使用zip
将停止在任何列表中首先结束,因此如果您有不均匀长度的列表,则项目将被删除。
编辑 - 以下是执行此操作的另一种方法,其中显式递归以可通过映射实现主要功能的方式隔离
另一种解决方法是首先将Model2分组到一个列表列表中,其中每个项目包含等效Model1条目的适当数量的元素。
为此,我将定义一个函数takes
,它将列表拆分为多个较小的列表,这些列表的大小作为第一个参数传入。
takes : List Int -> List a -> List (List a)
takes counts list =
case counts of
[] -> []
(x::xs) -> List.take x list :: takes xs (List.drop x list)
现在,您可以使用takes
功能对Model2列表进行分组,允许您将其映射到Model1输入,以便您可以压缩内部列表。
toViewModel : Model1 a b -> Model2 c -> ViewModel a b c
toViewModel model1 model2 =
let
m2Grouped = takes (List.map (List.length << snd) model1) model2
mapper (m1ID, m1List) m2List = (m1ID, zip m1List m2List)
in
List.map2 mapper model1 m2Grouped
答案 1 :(得分:1)
这是一个稍微简单的任务:
List (a, b)
Model1
Model2
合并,以获取List (a, b, c)
来自两个列表的数据a
对列表进行分组,以List.filterMap List (a, List (b, c))
醇>
我不得不模拟一些数据来运行测试。
请考虑以下示例:
import Graphics.Element exposing (show)
-- List (a, List b)
type alias Model1 = List (String, List Int)
-- List c
type alias Model2 = List Bool
-- List (a, List (b, c))
type alias ViewModel = List (String, List (Int, Bool))
toViewModel : Model1 -> Model2 -> ViewModel
toViewModel model1 model2 =
let
-- Map merge both lists and map values to the grouping key.
mappedList =
model1
|> List.concatMap (\(groupBy, list) -> List.map (\el -> (groupBy, el)) list)
|> List.map2 (\val2 (groupBy, val1) -> (groupBy, (val1, val2))) model2
-- Extract a list for for specified grouping key.
getListByKey search =
List.filterMap
(\(key, val) -> if key == search then Just val else Nothing)
mappedList
in
List.map (\(search,_) -> (search, getListByKey search)) model1
initModel1 : Model1
initModel1 =
[ ("foo", [ 1, 2, 3 ])
, ("bar", [ 4, 5, 6, 7])
]
initModel2 : Model2
initModel2 =
[ True
, False
, True
, False
, True
, False
, True
]
main =
toViewModel initModel1 initModel2
|> show