'Fastest way to get the last element of a list in Haskell

What is the fastest way to get the last element of a list in Haskell. Also in next iteration, I want to remove first and last element of the list. What is the most elegant way to do it? I am trying list comprehension, but that does not look very efficient!



Solution 1:[1]

You can use the last function to get the last element of a list.

As for how to remove the first and last elements, you could use (init . tail), but I don't know how efficient that is.

I think this image from Learn You A Haskell shows the list functions fairly well:

illustration of list functions

Solution 2:[2]

I'll post the Prelude implementation since it hasn't been posted yet:

listLast :: [a] -> a
listLast [x] = x --base case is when there's just one element remaining
listLast (_:xs) = listLast xs --if there's anything in the head, continue until there's one element left
listLast [] = error "Can't do last of an empty list!"

Note that I changed the function name to listLast so that it can be run without conflicting with normal Prelude. You could, of course, do import Prelude hiding(last).

Solution 3:[3]

To remove first and last:

take (len(l)-2) (drop 1 l)

or maybe

init (drop 1 l)

This also results in almost optimal code.

Solution 4:[4]

This answer focuses on dealing with weird conditions (like empty lists) in a maximally flexible way, and on building up bigger functions from smaller ones using some library functions. It's not the best answer for someone first learning about lists, but rather a couple steps past that.

For the following, you will need

import Control.Monad ((>=>))

and you will need to either use GHC 7.10 and import Data.List (uncons) or define

uncons :: [a] -> Maybe (a, [a])
uncons [] = Nothing
uncons (x:xs) = Just (x,xs)

You can write a safe form of init like this:

init' :: [x] -> Maybe [x]
init' = foldr go Nothing
  where
    go x mxs = Just (maybe [] (x:) mxs)

A version of tail can be written

tail' :: [a] -> Maybe [a]
tail' = fmap snd . uncons

So then you can get a maybefied

trim' :: [a] -> Maybe [a]
trim' = init' >=> tail'

The >=> is a sort of backwards monadic composition. init' >=> tail' is a function that applies init' to its argument to get a Maybe [a]. If it gets Nothing, it returns that. If it gets Just xs, it applies tail' to xs and returns that.

From this, you can easily make a trimmer that trims lists with 0, 1, or 2 elements down to empty lists:

trim :: [a] -> [a]
trim = maybe [] id . trim'

Solution 5:[5]

last' :: [a] -> a
last' ys = foldl1 (\_ -> \x -> x) ys

It is O(n), just like the built in library function list.

Solution 6:[6]

(head.reverse) [1..100]

Is an alternative to last to get the last element.

drop 1 (take (length [1..100] - 1) [1..100])

removes the first and last list element. The source for drop and take look like it might be faster than (init . tail).

(reverse.drop 1) ((reverse.drop 1) [1..100])

is another variant. But I guess slower because of the double reversal.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 George
Solution 2
Solution 3 nulvinge
Solution 4
Solution 5 Abhijit Gupta
Solution 6 orkoden