问题
I just started programming in Elm and am stuck at something:
I would like to have a method that can update fields of elements in a list at a certain index.
My signature would look like this:
updateElement : List (ID, Task) -> Int -> List (ID, Task)
with:
type alias Task =
{ description : String, focus : Bool}
In this case I would like to set the boolean (focus) of the task at the index given to true and all the others tasks in the list to false.
I already tried with arrays in Elm but then I have to work with Maybe and don't think that is a good solution.
I suppose I will have to work with 'map' to change elements in my list but I don't have any clue how I could change it at a particular index.
Thanks!
回答1:
Now that you've clarified your question, the real answer is a combination of the two updates Chad posted
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
回答2:
Since you want to update all elements in the list (to make sure all elements are either False while those matching the ID are True), you can perform a List.map over the list, while supplying a function whose job is to check the index and perform the update on the element.
Here's an example with a few minor changes to your example code:
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
I changed your signatures to be more generic. Since you provided no indication of what ID was, I assumed that the first element in the tuple had to match the type of whatever the second function parameter was. I also replaced Task with MyTask since there's already a common type in elm called Task.
I'll also mention that there is a List.indexedMap function which could let you simplify your function declaration a little bit. If the only reason you have a tuple input and output in your example above is because you need to locate an element by its index, it's probably easier to use List.indexedMap. Here's an example:
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
As you can see, it cuts some of that tuple boilerplate out of the function, making it a bit cleaner.
回答3:
If you want often to change only the nth element of a list, a List would be the wrong data structure. A List in elm is implemented as a linked list, which will not fare well in terms of performance with random access.
For that kind of work, you probably should rather use an elm Array, and indeed the Array does have a simple function to set the nth element, leaving all the others untouched: Array.set :: Int -> a -> Array a -> Array a.
On that topic, this discussion on the elm bug tracker could be of interest.
来源:https://stackoverflow.com/questions/34502706/elm-update-elements-in-a-list