I have a List
in my Elm model. On a Drag
message containing the previous index and next index (both zero-based) of an element, I want to move the element. This is the code that I am using now. I first convert to an Array
, then use slices to rearrange the array, finally converting back to a List
. Is there a better way (maybe not involving arrays). Note that the list will never have more than 5 items.
Drag { prev, next } ->
let
arr =
Array.fromList model.list
temp =
Array.append
(Array.slice 0 prev arr)
(Array.slice (prev + 1) (Array.length arr) arr)
list_ =
Array.toList <|
Array.append
(Array.append
(Array.slice 0 next temp)
(Array.slice prev (prev + 1) arr)
)
(Array.slice next (Array.length temp) temp)
model_ =
{ model | list = list_ }
in
( model_, Cmd.none )
If you find yourself using Array.slice
a lot, it's worth looking at the List.take
and List.drop
functions to see if they can do what you need!
For your example, it can be rewritten using List.take
, List.drop
, and List.concat
:
Drag { prev, next } ->
let
item =
List.drop prev model.list
|> List.take 1
rest =
List.concat
[ List.take prev model.list
, List.drop (prev + 1) model.list
]
reorderedList =
List.concat
[ List.take next rest
, item
, List.drop next rest
]
updatedModel =
{ model | list = reorderedList }
in
( updatedModel, Cmd.none )
I threw together a quick demo in Ellie that you can compare the two versions in.