Haskell:列出边界

时间:2013-03-17 18:51:06

标签: list haskell limit list-comprehension predicate

我有一个双打(myList)列表,我想添加到一个新的List(someList),但是一旦新列表达到设置大小,即25,我想停止添加它。我尝试使用sum实现此功能但未成功。示例代码如下。
someList = [(a)| a< - myList,sum someList< 30]

3 个答案:

答案 0 :(得分:2)

@DanielFischer表达这个问题的方式与Haskell的思维方式兼容。

  

你是否希望someList成为myList的最长前缀,其总和为< 30?

以下是我的接触方式:让我们说明一下

>>> let list = [1..20]

我们可以找到"累积总和"使用:

>>> let sums = tail . scanl (+) 0
>>> sums list
[1,3,6,10,15,21,28,36,45,55,66,78,91,105,120,136,153,171,190,210]

现在用原始列表压缩它以获得总和到那一点的元素对

>>> zip list (sums list)
[(1,1),(2,3),(3,6),(4,10),(5,15),(6,21),(7,28),(8,36),
 (9,45),(10,55),(11,66),(12,78),(13,91),(14,105),(15,120),
 (16,136),(17,153),(18,171),(19,190),(20,210)]

然后我们可以takeWhile这个列表来获取我们想要的前缀:

>>> takeWhile (\x -> snd x < 30) (zip list (sums list))
[(1,1),(2,3),(3,6),(4,10),(5,15),(6,21),(7,28)]

最后我们可以摆脱用于执行此计算的累积总和:

>>> map fst (takeWhile (\x -> snd x < 30) (zip list (sums list)))
[1,2,3,4,5,6,7]

请注意,由于懒惰,这与递归解决方案一样有效 - 只需要计算它们未通过测试的点的总和。这可以看出因为解决方案适用于无限列表(因为如果我们需要计算所有总和,我们永远不会完成)。

我可能会抽象出这个并将限制作为参数:

>>> :{
... let initial lim list =
...        map fst (takeWhile (\x -> snd x < lim) (zip list (sums list)))
... :}

此函数具有应满足的明显属性,即列表的总和应始终小于限制(只要限制大于0)。所以我们可以使用QuickCheck来确保我们做得对:

>>> import Test.QuickCheck
>>> quickCheck (\lim list -> lim > 0 ==> sum (initial lim list) < lim)
+++ OK, passed 100 tests.

答案 1 :(得分:0)

someList = makeList myList [] 0 where
    makeList (x:xs) ys total = let newTot = total + x
                               in if newTot >= 25
                                  then ys
                                  else makeList xs (ys ++ [x]) newTot

只要它们的总和小于25,就会从myList中获取元素。

逻辑发生在makeList。它接受输入列表的第一个元素并将其添加到运行总计中,以查看它是否大于25.如果是,我们不应将其添加到输出列表中,并且我们完成递归。否则,我们将x放在输出列表的末尾(ys)并继续使用输入列表的其余部分。

答案 2 :(得分:0)

您想要的行为是

ghci> appendWhileUnder 25 [1..5] [1..5]
[1,2,3,4,5,1,2,3]

因为总和为21并且加上4会使它达到25。

好的,一种解决方法是将++添加到appendWhileUnder n xs ys = takeWhileUnder n (xs++ys) ,然后选择25以下的初始段。

n

想要对中间列表进行求和,因此我会跟踪我允许的数量(takeWhileUnder n [] = [] takeWhileUnder n (x:xs) | x < n = x:takeWhileUnder (n-x) xs | otherwise = [] )。

x

我允许appendWhileUnder' n xs ys = xs ++ takeWhileUnder (n - sum xs) 通过,如果它没有超出我的余额。

可能不受欢迎的副作用:如果它总和超过25,它会砍掉原始列表的位。解决方法:使用

xs

保留整个n是否会让您超过{{1}}。