22

I was suprised to learn that Array and List were two different types in Elm:

In my case, I have a List Int of length 2,000,000 and I need about 10,000 of them but I don't know in advance which ten thousand. That will be provided by another list. In pseudo-code:

x = [ 1,1,0,30,...,255,0,1 ]
y = [ 1,4,7,18,36,..., 1334823 , ... 1899876 ]
z = [ y[x[0]], y[x[1]], ... ]

I am using pseudocode because clearly this isn't Elm syntax (it might be legal JavaScript).

Can these array selections be done in List or Array or both?

john mangual
  • 7,718
  • 13
  • 56
  • 95
  • `List` is a linked-list structure, so the expression `y[x[i]]` is an O(n) lookup for the `i`th in `x` plus another O(n) lookup for the element in `y`. In other words, for 10000 lookups among 2mil elements this will be prohibitively slow. Use Array. – Alex Reinking Jun 08 '16 at 16:09
  • Unless `y` is guaranteed to be sorted, then a different algorithm will work – Alex Reinking Jun 08 '16 at 16:13
  • Just out of curiosity: what's the broader problem your solving by picking 10.000 elements out of a 2.000.000 element list? – Søren Debois Jun 08 '16 at 18:00
  • the 2 million elements are pixels from an image. I am given 10000 points and I need to find their RGB color. I can ask a new question if you like – john mangual Jun 08 '16 at 19:45

3 Answers3

45

List is a linked list which provides O(n) lookup time based on index. Getting an element by index requires traversing the list over n nodes. An index lookup function for List isn't available in the core library but you can use the elm-community/list-extra package which provides two functions for lookup (varying by parameter order): !! and getAt.

Array allows for O(log n) index lookup. Index lookups on Array can be done using Array.get. Arrays are represented as Relaxed Radix Balanced Trees.

Both are immutable (all values in Elm are immutable), so you have trade-offs depending on your situation. List is great when you make a lot of changes because you are merely updating linked list pointers, whereas Array is great for speedy lookup but has somewhat poorer performance for modifications, which you'll want to consider if you're making a lot of changes.

Chad Gilbert
  • 36,115
  • 4
  • 89
  • 97
  • 2
    I didn't check, but I'd have thought Array was some form of red-black tree with O(lg n) lookup? – Søren Debois Jun 08 '16 at 17:58
  • @SørenDebois you are absolutely right, the lookup is O(lg n) in Elm's `Array` – halfzebra Jun 08 '16 at 18:30
  • 1
    Looks like Array is using [Relaxed Radix Balanced Trees](http://elm-lang.org/blog/announce/0.12.1#arrays) under the hood. I've updated my answer. – Chad Gilbert Jun 08 '16 at 18:31
  • For folding or mapping over, what is better, `Array` or `List`? – fiatjaf Oct 06 '16 at 02:54
  • In general terms, `List` will have better performance for folding and mapping because it's "one step" to the next item. `Array`s will be better for indexed lookups but perform slightly worse for folding and mapping because they have a few more steps to get to the next element. – Chad Gilbert Oct 06 '16 at 02:59
1

Something like this should work:

import Array
import Debug

fromJust : Maybe a -> a
fromJust x = case x of
    Just y -> y
    Nothing -> Debug.crash "error: fromJust Nothing"

selectFromList : List a -> List Int -> List a
selectFromList els idxs = 
  let arr = Array.fromList els
   in List.map (\i -> fromJust (Array.get i arr)) idxs

It converts the input list to an array for fast indexing, then maps the list of indices to their corresponding values in the array. I took the fromJust function from this StackOverflow question.

Community
  • 1
  • 1
Alex Reinking
  • 16,724
  • 5
  • 52
  • 86
0

Only use Array if you need to use Array.get.

In most cases you should use List because usually you can do everything you need with foldl, map, etc. without having to get items from an index, and List has better performance with these functions.

Dull Bananas
  • 892
  • 7
  • 29