I am having trouble solving a quite simple problem in Elm. I am pretty new to the functional paradigm so there might be a “good” way to solve this.
Given a List of Image. Each Image has quite a few properties but also an id.
I would like to access an image given an Idand get the previous and following element.
What would be the best way to handle this situation ? Should I use a Array instead of a List?
To access neighboring elements of a list, you need to use tail recursion. Here’s a solution using that:
findWithNeighbors : (a -> Bool) -> List a -> ( Maybe a, Maybe a, Maybe a )
findWithNeighbors pred list =
case list of
a :: b :: c :: rest ->
if pred b then
( Just a, Just b, Just c )
else if pred a then
( Nothing, Just a, Just b )
else
findWithNeighbors pred (b :: c :: rest)
a :: b :: [] ->
if pred a then
( Nothing, Just a, Just b )
else if pred b then
( Just a, Just b, Nothing )
else
findWithNeighbors pred [ b ]
a :: [] ->
if pred a then
( Nothing, Just a, Nothing )
else
( Nothing, Nothing, Nothing )
[] ->
( Nothing, Nothing, Nothing )
Usage:
findWithNeighbors (\i -> i == 1) [1,2,3] -- (Nothing, Just 1, Just 2)
findWithNeighbors (\i -> i == 2) [1,2,3] -- (Just 1, Just 2, Just 3)
findWithNeighbors (\i -> i == 3) [1,2,3] -- (Just 2, Just 3, Nothing)
Alternatively you could use List.Extra.findIndex and then call List.Extra.getAt three times, with index - 1 and index + 1, although it’d be less efficient.
I will give this solution a try. The list might contain a large number of elements (up to tens of thousands) so I will need to compare both solutions for different given ranges.
I would be tempted to make my model reflect this kind of requirement instead of implementing a function to infer the current, prev, and next images. At least it seems to me that such a requirement would be better met by modelling it explicitly.
type ImageModel =
{ previous = List Image
, current = (Maybe Image, Maybe Image, Maybe Image)
, next = List Image
}
Depending on your use case you could even go further and maintain something like this for even more explicitness.
type ImageModel
= NoImages
| OnlyTwo ( Image, Image )
| OnlyThree ( Image, Image, Image )
| More
{ prev : List Image
, current : ( Image, Image, Image )
, next : List Image
}
I have often profited from maintaining very explicit models like this rather than having a simple model with complex functions extracting the data I needed from it. The guarantees and explicitness in such models are quite useful.