考虑以下函数来查找列表的倒数第二个元素:
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)?
答案 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