Many times I see functions which operate on the head of a list, e.g:
trimHead ('\n':xs) = xs
trimHead xs = xs
then I see the the definition:
trimTail = reverse . trimHead . reverse
then I see:
trimBoth = trimHead . trimTail
They are clean, but are trimTail
and trimBoth
efficient? Is there a better way?
Using Swapping Instead, we reverse the original array itself. In this method, we swap the elements of the array. The first element is swapped with the last element. The second element is swapped with the last but one element and so on.
The fastest way would be to use the reverse() method on the StringBuilder or StringBuffer classes :) You could also run half the array length and swap the chars, the checks involved slow things down probably. Save this answer.
By Using StringBuilder StringBuilder or StringBuffer class has an in-build method reverse() to reverse the characters in the string. This method replaces the sequence of the characters in reverse order. The reverse method is the static method that has the logic to reverse a string in Java.
Consider this alternative implementation
trimTail2 [] = []
trimTail2 ['\n'] = []
trimTail2 (x:xs) = x : trimTail2 xs
trimBoth2 = trimHead . trimTail2
It's easy to confirm that trimTail
and trimBoth
require that the entire list be evaluated, while trimTail2
and trimBoth2
only evaluate as much of the list as is necessary.
*Main> head $ trimTail ('h':undefined)
*** Exception: Prelude.undefined
*Main> head $ trimBoth ('h':undefined)
*** Exception: Prelude.undefined
*Main> head $ trimTail2 ('h':undefined)
'h'
*Main> head $ trimBoth2 ('h':undefined)
'h'
This implies that your version is going to be less efficient if the whole result is not needed.
Assuming the whole list is to be evaluated (if you don't need the whole list, why are you trimming the end?), it's about half as efficient as you can get out of immutable lists, but it has the same asymptotic complexity O(n).
The new list requires at least:
reverse . trimHead . reverse
performs roughly twice this:
reverse
performs n pointer traversals and n cons.trimHead
possibly performs 1 pointer traversal.reverse
performs n pointer traversals and n cons.Is this worth worrying about? In some circumstances, maybe. Is the code too slow, and is this called a lot? In others, maybe not. Benchmark! The implementation with reverse
is nice and easy to understand, and that's important.
There is a fairly natural recursive step-through-the-list solution, which will only evaluate as much of the output as is consumed, so in the case that you don't know whether you need the whole string, you can possibly save some evaluation.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With