Home > Blockchain >  Remove only the first occurrence of an item from a list in elm
Remove only the first occurrence of an item from a list in elm

Time:10-10

Let's say I have a list of characters

letters = ['B','A', 'M', 'B', 'A']

I want a function that will remove the first instance a given character

removeSingleItem letters 'A'
-- ['B','M', 'B', 'A']

I can do this using recursion

removeSingleItem list item new =
    case list of
        [] -> new
        (x::xs) -> 
            if x == item then
                new    xs
             else 
                removeSingleItem xs item (new    [x])

But I feel this is a verbose solution, but I cannot see a way to do this with List.filter without removing all the matching items.

Is there a simpler way to do this using core List operations

CodePudding user response:

The bigger problem with your code is that it is very inefficient because it keeps unnecessarily concatenating and creating new lists. It's possible to make it both much more efficient, simpler and slightly less verbose as a recursive function:

removeSingleItem list item =
    case list of
        [] -> []
        x :: xs ->
            if x == item then
                xs
            else
                x :: removeSingleItem xs item

Although do note that this is not tail recursive, so it will not work on large lists, but I don't see that being mentioned as a requirement. It is of course possible to make it tail recursive as well, while still being much more efficient, but at the cost of some additional complexity.

You could also do it using a fold (such as List.foldl), but that definitely wouldn't be simpler, or less verbose.

And if you don't mind taking on a dependency, this funcction already exists in list-extra as List.Extra.remove (which is tail recursive).

  • Related