Search code examples
arraysswapelm

Swap two elements in elm Array


I would like to do a function to swap two elements in array.

Obviously if it is triggered Up msg with first element, nothing will happens. Same if Down msg with latest element.

I have the following code:

module Main exposing (main)

import Browser
import Html exposing (Html, button, div, text)
import Html.Attributes exposing (class)
import Html.Events exposing (onClick)
import Array
import List exposing (map)

type alias Model = Array.Array Int


initialModel : Model
initialModel =
    Array.fromList [3, 1, 7, 2, 6, 4, 5]


type Msg
    = Up Int
    | Down Int


update : Msg -> Model -> Model
update msg model =
    case msg of
        Up n ->
           swap model n (n-1)
        Down n ->
           swap model n (n+1)

swap : Model -> Int -> Int -> Model
swap model src dest =
   model -- How do it?


view : Model -> Html Msg
view model =
    div [] (map elements (Array.toIndexedList model))

elements : (Int, Int) -> Html Msg
elements (position, number) =
  div [ class "block" ]
    [ button [ onClick (Up position) ] [ text "UP" ]
    , div [] [ text <| String.fromInt number ]
    , button [ onClick (Down position) ] [ text "DOWN" ]
    ]


main : Program () Model Msg
main =
    Browser.sandbox
        { init = initialModel
        , view = view
        , update = update
        }

And I would like to know if it is better using List or Array to do that.

Thank you very much


Solution

  • I would generally prefer to use a List instead of Array, but if you don't plan to add new items to your list, an Array would likely make more sense.

    A pro of Array is that accessing a specific element is faster, but if you only have a few items you probably won't have to worry about performance. Also converting from Array to List is also not without performance costs.

    Option 1: If you keep using an Array, you could solve it e.g. like this:

    1. Get the values at src and dest and bail early if one of them returns Nothing (this will cover the cases where a index is out of bounds)
    2. Set the value of src to dest and the other way around
    3. Return the new array

    Option 2: If you use a List instead, you could for instance use the elm-community/list-extra package.
    It has a swapAt function that does what you need.

    Option 3: Can be implemented for either List or Array, but you will need to implement a custom behavior that traverses all the elements and builds a new Array/List, which is out of scope for now I think.

    Regards, marc