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