Haskell中列表的倒数第二个元素

时间:2015-10-11 18:14:03

标签: haskell

考虑以下函数来查找列表的倒数第二个元素:

myButLast (x:xs) = if length xs > 1 then myButLast xs else x

这是一个O(n ^ 2)算法,因为length xs是O(n)并且被称为O(n)次。在Haskell中写这个的最优雅的方法是什么,length一旦超过1就停止,这样算法就是O(n)?

6 个答案:

答案 0 :(得分:9)

最简单的方法是避免length

myButLast (x : _ : []) = x  -- base case
myButLast (_ : xs)     = myButLast xs

Haskell中关于模式的权威性参考是语言报告:https://www.haskell.org/onlinereport/haskell2010/haskellch3.html#x8-580003.17

GHC实现了https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/syntax-extns.html#pattern-guards所述的一些扩展。

答案 1 :(得分:6)

怎么样

myButLast []     = error "oho"
myButLast [x,_]  = x
myButLast (_:xs) = myButLast xs

答案 2 :(得分:5)

利用zip

\l -> fst . last $ zip l (tail l)

还有一种毫无意义的混淆风格:

fst . last . (zip <*> tail)

甚至没有括号(感谢@melpomene):

fst . last . ap zip tail

其他变体:

last . ap (zipWith const) tail

答案 3 :(得分:4)

另一种解决方案:

myButLast [] = error "List is empty"
myButLast [x] = error "List is a singleton"
myButLast xs = last $ init xs

答案 4 :(得分:1)

这是我使用前奏中的tail函数的解决方案

M2

答案 5 :(得分:1)

另一个基于zip的解决方案,无需明确压缩。妥善保管好安全性。

import Data.Maybe

g :: Int -> [a] -> Maybe a
g i = (head <$>) . listToMaybe . reverse         -- quick'n'dirty safe-last
                 . getZipList . traverse ZipList 
                 . sequence [id, drop i] 

g  1 [1..10] => Just 9
g  3 [1..10] => Just 7
g 13 [1..10] => Nothing