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!
The List, Tuples and Record data structures can be used to store a collection of values. This chapter discusses how to use List in Elm. A List is a collection of homogeneous values. The values in a list must all be of the same data type. Consider the following limitations while using variables to store values − Variables are scalar in nature.
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:
In Elm there are different kinds of data structures that can contain elements. This article spotlights the iterable structures lists, arrays, sets and dictionaries, which support the basic operations of functional programming like map, filter and folding/reducing.
This function returns the first element from input list. To check the signature of function, type the following in elm REPL − This function returns all elements after first in the list. The cons operator ( :: ) adds an element to the front of a list. The new element to be added and the data-type of the values in the list must match.
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
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With