开发者

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 iterati开发者_JAVA百科on, 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!


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:

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


last and init will do the job just fine for a one-off. However they are both O(n), so if you need to manipulate both ends of a list often, as you seem to imply, you might want to consider using Data.Sequence instead, which supports O(1) insertion and removal of items at both ends.


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


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.


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'


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

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


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

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜