在索引处打破列表

时间:2013-01-03 15:21:25

标签: performance haskell

我今天有一个表现问题。

我正在制作一个(Haskell)程序,在进行性能分析时,我发现大部分时间花在了下面的功能中。它的目的是获取列表的第n个元素,并返回除了元素本身之外没有它的列表。我目前的(慢)定义如下:

breakOn :: Int -> [a] -> (a,[a])
breakOn 1 (x:xs) = (x,xs)
breakOn n (x:xs) = (y,x:ys)
 where
  (y,ys) = breakOn (n-1) xs

已知Int参数位于1..n范围内,其中n是(永不为空)列表(x:xs)的长度,因此函数永远不会出现错误。

然而,我在这里表现不佳。我的第一个猜测是我应该更改另一个结构的列表。但是,在开始选择不同的结构和测试代码(这将花费我很多时间)之前,我想在这里询问第三人的意见。另外,我很确定我没有以最好的方式做到这一点。欢迎任何指示!

请注意,a类型可能不是Eq的实例。

解决方案

我在Data.Sequence模块中调整了我的代码使用Sequence s。结果如下:

import qualified Data.Sequence as S

breakOn :: Int -> Seq a -> (a,Seq a)
breakOn n xs = (S.index zs 0, ys <> (S.drop 1 zs))
 where
  (ys,zs) = S.splitAt (n-1) xs

但是,我仍然接受进一步的改进建议!

2 个答案:

答案 0 :(得分:9)

是的,效率低下。使用splitAt(在递归位期间将数字解除容器)可以做得更好,通过使用具有有效分割的数据结构,例如, a fingertree,最好通过按摩上下文来避免需要此操作。如果您发布更多上下文,则可以提供更有针对性的建议。

答案 1 :(得分:4)

Prelude功能通常非常有效。您可以使用splitAt重写您的函数,如下所示:

breakOn :: Int -> [a] -> (a,[a])
breakOn n xs = (z,ys++zs)
 where
  (ys,z:zs) = splitAt (n-1) xs