如何将列表嵌套到给定列表中的大小的子列表中?

时间:2015-11-02 03:18:51

标签: haskell

我刚开始学习Haskell,正在尝试使用Project Euler。

我有一个数字列表,我想创建一个二维列表,分成另一个列表中定义的长度的子列表。

所以,我喜欢一个函数,它接受一个I​​nts列表和一个长度列表,并对它们进行操作:

f [1..20] [5,8,6] = [[1,2,3,4,5],[6,7,8,9,10,11,12,13],[14,15,16,17,18,19]]

如果函数可以获取无限的数字和长度列表并且只是保持子列表,那将会很棒。

我不知道如何解决这个问题。看看Stack Overflow,我看到(对我的新手来说相当复杂)将列表打包到相同长度的子列表中的解决方案,但不像我感兴趣的那样。

1 个答案:

答案 0 :(得分:0)

让我们根据您的规范使用递归来实现以下功能:

splitAts :: [a] -> [Int] -> [[a]]

请注意,我已经翻转了参数的顺序,因为这样,部分应用的函数splitAts n可以被认为是有意义的操作,给定任何列表,将它分成子列表给定长度。

简单的情况是指定没有(更多)子列表长度:

splitAts [] xs = []

递归的情况是当第一个子列表长度为n时:在这种情况下,我们返回的第一个子列表将具有此长度,其余的将仅仅是根据列表的其余部分的拆分其余的长度:

splitAts (n:ns) xs = take n xs : splitAts ns (drop n xs)

已经存在一个函数splitAt,可以在一次扫描中执行take n / drop n,因此上述内容可以重写为效果更好的

splitAts (n:ns) xs = here : splitAts ns there
  where
    (here, there) = splitAt n xs

示例运行:

*Main> splitAts [5, 8, 6] [1..20]
[[1,2,3,4,5],[6,7,8,9,10,11,12,13],[14,15,16,17,18,19]]

这很懒惰:不仅仅是这样:

*Main> splitAts [5, 8, 6] [1..]
[[1,2,3,4,5],[6,7,8,9,10,11,12,13],[14,15,16,17,18,19]]    

但是这个也是:

*Main> take 10 (splitAts [3,5..] [1..])
[[1,2,3],[4,5,6,7,8],[9,10,11,12,13,14,15],[16,17,18,19,20,21,22,23,24],
[25,26,27,28,29,30,31,32,33,34,35],[36,37,38,39,40,41,42,43,44,45,46,47,48]]