榆树 - 更新列表中的元素

时间:2015-12-29 00:19:36

标签: arrays list indexing elm

我刚刚开始在Elm编程并且遇到了困难:

我想有一个方法可以在某个索引处更新列表中元素的字段。

我的签名将如下所示:

updateElement : List (ID, Task) -> Int -> List (ID, Task)

with:

type alias Task =
  { description : String, focus : Bool}

在这种情况下,我想将任务的布尔(焦点)设置为给定为true的索引,将列表中的所有其他任务设置为false。

我已经尝试过使用Elm中的数组,但后来我必须使用Maybe,并且不要认为这是一个很好的解决方案。

我想我将不得不与地图'更改我的列表中的元素,但我不知道如何在特定索引处更改它。

谢谢!

3 个答案:

答案 0 :(得分:6)

现在您已经澄清了您的问题,真正的答案是Chad发布的两个更新的组合

updateElement : List (ID, Task) -> Int -> List (ID, Task)
updateElement list indexToFocusOn =
  let
    toggle index (id, task) =
      if index == indexToFocusOn then
        (id, { task | focus = true })
      else
        (id, { task | focus = false })
  in
    List.indexedMap toggle list

答案 1 :(得分:4)

由于您要更新列表中的所有元素(为了确保所有元素都为False而匹配ID的元素为True),您可以在列表上执行List.map,同时提供其作业的函数是检查索引并对元素执行更新。

以下是对示例代码进行一些细微更改的示例:

type alias MyTask =
  { description : String
  , focus : Bool
  }

updateElement : List (a, MyTask) -> a -> List (a, MyTask)
updateElement list id =
  let
    toggle (idx, task) =
      if id == idx then
        (idx, { task | focus = True })
      else
        (idx, { task | focus = False })
  in
    List.map toggle list

我将您的签名更改为更通用。由于你没有提供ID是什么的指示,我假设元组中的第一个元素必须匹配第二个函数参数的类型。我还将Task替换为MyTask,因为在elm中已经有一个名为Task的常见类型。

我还提到有一个List.indexedMap函数可以让你简化函数声明。如果你在上面的例子中有一个元组输入和输出的唯一原因是你需要通过索引找到一个元素,那么它可能更容易使用List.indexedMap。这是一个例子:

updateElement2 : List MyTask -> Int -> List MyTask
updateElement2 list id =
  let
    toggle idx task =
      if id == idx then
        { task | focus = True }
      else
        { task | focus = False }
  in
    List.indexedMap toggle list

正如你所看到的那样,它会从函数中删除一些元组样板,使它更清晰。

答案 2 :(得分:4)

如果您经常只想更改列表的第n个元素,List将是错误的数据结构。榆树中的List被实现为链接列表,在随机访问的性能方面表现不佳。

对于这类工作,您可能应该使用elm Array,而且Array确实有一个简单的函数来设置第n个元素,而其他所有元素都保持不变:Array.set :: Int -> a -> Array a -> Array a。< / p>

关于该主题,this discussion on the elm bug tracker可能会引起人们的兴趣。