Haskell 以有效的方式从列表中获取最后一个元素

Haskell 以有效的方式从列表中获取最后一个元素,haskell,Haskell,在Haskell中获取列表的最后一个元素最有效的方法是什么 示例:getLastElement[1,2,3,4]应返回4 据我所知,last[1,2,3,4]不是很有效,因为Haskell在列表中搜索,结果效率为O(n),其中n是列表的长度。就是说列表数据结构正确吗?如果您想要最后一个元素,您将拥有O(n)复杂性。这是不可能的 你必须考虑一个不同的数据结构,比如内置的列表,没有O(n)复杂度(你只能得到第一个元素,而其他列表中的每一个,如果你不经过所有n个元素就不能结束).首先请注意,last在

在Haskell中获取列表的最后一个元素最有效的方法是什么

示例:
getLastElement[1,2,3,4]
应返回
4


据我所知,
last[1,2,3,4]
不是很有效,因为Haskell在列表中搜索,结果效率为
O(n)
,其中
n
是列表的长度。

就是说列表数据结构正确吗?如果您想要最后一个元素,您将拥有
O(n)
复杂性。这是不可能的


你必须考虑一个不同的数据结构,比如

内置的列表,没有O(n)复杂度(你只能得到第一个元素,而其他列表中的每一个,如果你不经过所有n个元素就不能结束).

首先请注意,
last
在其他方面不是特别好,因为它是一个类似于
head
的部分函数。如果您一直在使用列表的末尾,请将其废弃为
Data.Sequence
Data.Vector.unbox

import Data.Sequence

firstThing seq = case viewl seq of
   EmptyL -> error "no beginning"
   a :< as -> a

lastThing seq = case viewr seq of
   EmptyR -> error "no end"
   as :> a -> a

-- > lastThing (fromList "abc")
-- 'c'
-- > firstThing (fromList "abc")
-- 'a'
导入数据。顺序
第一件事序号=案例视图序号
清空->错误“无开始”
a:a
lastThing seq=案例视图seq of
清空->错误“无结束”
as:>a->a
-->最后一件事(来自列表“abc”)
--“c”
-->第一件事(来自列表“abc”)
--“a”
如果您使用的是未装箱类型,如
Int
Double
Char
等,那么使用
Data.Vector.unbox
将获得更好的结果,请参阅文档以了解
Data.Vector.unbox.head
Data.Vector.unbox.last

在使用
Char
s列表的特殊情况下,尽可能使用
Data.Text
,这显然是“惯用的”东西。再次参见
头部
最后一个


如果你想象的是“Haskell”列表和其他语言中的“列表”之间的对比,那么可能是“Haskell”列表与向量和数组之间的对比;后者与列表一样是“haskell”。

冈崎的书教给我们一个向现有数据结构添加高效API的好技巧:将结构封装在一个新的结构中,该结构缓存API调用的结果。如果您只想将
last
添加到高效调用集合中,以下是简单的方法:

import Control.Monad -- mplus is a convenient spell

data LastList a = LastList
    { forget :: [a]
    , last   :: Maybe a
    }

nil = LastList [] Nothing
cons x l = LastList (x : forget l) (last l `mplus` Just x)

现在,
最后一个
操作是O(1),很简单。这是非常有限的:您无法有效地修改列表的结尾,或者有效地获取倒数第二个元素,或者高效地从列表中构建其中一个元素(因此您必须在整个代码中用这些家伙替换所有基于列表的函数以查看其好处),或者诸如此类的事情,但您要求提高效率的一个方法是。

由于列表的构建方式,没有其他方法可以做到这一点。