# How to get a given element in list by id and the previous and next element?

Hi there !

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 `Id` and 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`?

Thanks !

I think using List.Extra (https://package.elm-lang.org/packages/elm-community/list-extra/8.2.3/List-Extra) you would be able to do what you want, in particular with `find` and `getAt`.

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.

4 Likes

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.

Thanks a lot !

Really nice solution!!!

I’m not sure this is relevant for your case:

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.

I would do something like Richard Feldman recommends here https://www.youtube.com/watch?v=x1FU3e0sT1I

Maybe it would look like this

``````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.

3 Likes

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.