如何将奇形怪状的名单压缩成榆树?

时间:2016-05-03 15:02:01

标签: elm

我想在我的Elm程序中组合两个数据结构。他们的类型是Syndication_publication = 1List (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个元素压缩。

这是上一个例子的图表:

Diagram of example drawn on paper

如何构建toViewModel函数?

2 个答案:

答案 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)

这是一个稍微简单的任务:

  1. 使用List.concatMapList (a, b)
  2. 创建广告Model1
  3. 将其与Model2合并,以获取List (a, b, c)来自两个列表的数据
  4. a对列表进行分组,以List.filterMap
  5. 获得最终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