Skip to content

Instantly share code, notes, and snippets.

@Janiczek
Last active March 10, 2026 17:17
Show Gist options
  • Select an option

  • Save Janiczek/b04e9aebe51f3f06888f37c7952d3032 to your computer and use it in GitHub Desktop.

Select an option

Save Janiczek/b04e9aebe51f3f06888f37c7952d3032 to your computer and use it in GitHub Desktop.
Array vs Dict vs IntDict benchmark

100 inserts / 1k gets

PreallocatedArray   270.926 us/run
Array               274.428 us/run
IntDict             322.264 us/run
Dict                323.860 us/run
PreallocatedDict    337.868 us/run
PreallocatedIntDict 342.996 us/run
PreallocatedList    425.608 us/run
List                501.995 us/run

1k inserts / 10k gets

PreallocatedArray    3.862839 ms/run 
Array                3.902990 ms/run 
Dict                 4.815101 ms/run 
PreallocatedDict     5.063761 ms/run 
IntDict              5.080477 ms/run 
PreallocatedIntDict  5.379815 ms/run 
PreallocatedList    20.278291 ms/run
List                28.337324 ms/run

Using elm-bench like:

$ elm-bench \
    -f Main.runOnList \
    -f Main.runOnArray \
    -f Main.runOnDict \
    -f Main.runOnIntDict \
    -f Main.runOnPreallocatedList \
    -f Main.runOnPreallocatedArray \
    -f Main.runOnPreallocatedDict \
    -f Main.runOnPreallocatedIntDict \
    0 10000 100000
{
"type": "application",
"source-directories": [
"src"
],
"elm-version": "0.19.1",
"dependencies": {
"direct": {
"elm/browser": "1.0.2",
"elm/core": "1.0.5",
"elm/html": "1.0.1",
"elm/random": "1.0.0",
"elm-community/intdict": "3.1.0",
"elm-community/random-extra": "3.2.0",
"elmcraft/core-extra": "2.3.0"
},
"indirect": {
"elm/json": "1.1.4",
"elm/regex": "1.0.0",
"elm/time": "1.0.0",
"elm/url": "1.0.0",
"elm/virtual-dom": "1.0.5"
}
},
"test-dependencies": {
"direct": {},
"indirect": {}
}
}
module Main exposing
( runOnArray
, runOnDict
, runOnIntDict
, runOnList
, runOnPreallocatedArray
, runOnPreallocatedDict
, runOnPreallocatedIntDict
, runOnPreallocatedList
)
import Array
import Array.Extra
import Dict
import IntDict
import List.Extra
import Random
import Random.List
runOnArray : Int -> Int -> Int -> ()
runOnArray seed0 insertedItems accessedItems =
run
{ init = \_ -> Array.empty
, insert =
\i v acc ->
case Array.get i acc of
Nothing ->
acc
|> Array.Extra.resizelRepeat (i + 1) 0
|> Array.set i v
Just _ ->
Array.set i v acc
, access = Array.get
}
seed0
insertedItems
accessedItems
runOnPreallocatedArray : Int -> Int -> Int -> ()
runOnPreallocatedArray seed0 insertedItems accessedItems =
run
{ init = \n -> Array.repeat n 0
, insert = Array.set
, access = Array.get
}
seed0
insertedItems
accessedItems
runOnDict : Int -> Int -> Int -> ()
runOnDict seed0 insertedItems accessedItems =
run
{ init = \_ -> Dict.empty
, insert = Dict.insert
, access = Dict.get
}
seed0
insertedItems
accessedItems
runOnPreallocatedDict : Int -> Int -> Int -> ()
runOnPreallocatedDict seed0 insertedItems accessedItems =
run
{ init = \n -> List.range 1 n |> List.map (\x -> ( x, x )) |> Dict.fromList
, insert = Dict.insert
, access = Dict.get
}
seed0
insertedItems
accessedItems
runOnIntDict : Int -> Int -> Int -> ()
runOnIntDict seed0 insertedItems accessedItems =
run
{ init = \_ -> IntDict.empty
, insert = IntDict.insert
, access = IntDict.get
}
seed0
insertedItems
accessedItems
runOnPreallocatedIntDict : Int -> Int -> Int -> ()
runOnPreallocatedIntDict seed0 insertedItems accessedItems =
run
{ init = \n -> List.range 1 n |> List.map (\x -> ( x, x )) |> IntDict.fromList
, insert = IntDict.insert
, access = IntDict.get
}
seed0
insertedItems
accessedItems
runOnList : Int -> Int -> Int -> ()
runOnList seed0 insertedItems accessedItems =
run
{ init = \_ -> []
, insert =
\i v acc ->
let
len =
List.length acc
missing =
i - len + 1
in
if missing > 0 then
(acc ++ List.repeat missing 0)
|> List.Extra.setAt i v
else
List.Extra.setAt i v acc
, access = List.Extra.getAt
}
seed0
insertedItems
accessedItems
runOnPreallocatedList : Int -> Int -> Int -> ()
runOnPreallocatedList seed0 insertedItems accessedItems =
run
{ init = \n -> List.range 1 n
, insert = List.Extra.setAt
, access = List.Extra.getAt
}
seed0
insertedItems
accessedItems
type alias RunConfig a =
{ init : Int -> a
, insert : Int -> Int -> a -> a
, access : Int -> a -> Maybe Int
}
run : RunConfig a -> Int -> Int -> Int -> ()
run config seed insertedItems accessedItems =
let
seed0 =
Random.initialSeed seed
rawInsertIndices =
List.range 0 (insertedItems - 1)
( shuffledInsertIndices, seed1 ) =
Random.step (Random.List.shuffle rawInsertIndices) seed0
insertIndices =
shuffledInsertIndices
|> List.indexedMap (\v i -> ( i, v ))
rawAccessIndices =
List.Extra.cycle accessedItems rawInsertIndices
( shuffledAccessIndices, _ ) =
Random.step (Random.List.shuffle rawAccessIndices) seed1
insertMany : List ( Int, Int ) -> a -> a
insertMany indices acc =
case indices of
[] ->
acc
( i, v ) :: rest ->
insertMany rest (config.insert i v acc)
accessMany : List Int -> a -> ()
accessMany indices acc =
case indices of
[] ->
()
index :: rest ->
let
_ =
config.access index acc
in
accessMany rest acc
in
config.init insertedItems
|> insertMany insertIndices
|> accessMany shuffledAccessIndices
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment