比较haskell中的3个输出列表

时间:2009-08-13 09:08:37

标签: haskell

我正在做另一个Project Euler问题,我需要找到这三个列表的结果相等的时候(我们第一次给出40755它们是相同的,我需要找到下一个:

hexag n = [ n*(2*n-1)   | n <- [40755..]] 
penta n = [ n*(3*n-1)/2 | n <- [40755..]] 
trian n = [ n*(n+1)/2   | n <- [40755..]] 

我尝试在其他列表中添加第一个列表的谓词,但这不起作用:

hexag n = [ n*(2*n-1)   | n <- [40755..], penta n == n, trian n == n] 

我被困在哪里可以离开这里。

我尝试绘制函数甚至微积分,但无济于事,所以我必须求助于Haskell解决方案。

4 个答案:

答案 0 :(得分:2)

  • 你的功能很奇怪。他们得到n然后忽略它?
  • 您还会在功能的输入和输出之间产生混淆。第40755号六边形数字是3321899295,而不是40755。

如果你真的想要一个扰流板来解决这个问题(但是没有错过这一点?):

binarySearch :: Integral a => (a -> Bool) -> a -> a -> a
binarySearch func low high
  | low == high = low
  | func mid = search low mid
  | otherwise = search (mid + 1) high
  where
    search = binarySearch func
    mid = (low+high) `div` 2

infiniteBinarySearch :: Integral a => (a -> Bool) -> a
infiniteBinarySearch func =
  binarySearch func ((lim+1) `div` 2) lim
  where
    lim = head . filter func . lims $ 0
    lims x = x:lims (2*x+1)

inIncreasingSerie :: (Ord a, Integral i) => (i -> a) -> a -> Bool
inIncreasingSerie func val =
  val == func (infiniteBinarySearch ((>= val) . func))

figureNum :: Integer -> Integer -> Integer
figureNum shape index = (index*((shape-2)*index+4-shape)) `div` 2

main :: IO ()
main =
  print . head . filter r $ map (figureNum 6) [144..]
  where
    r x = inIncreasingSerie (figureNum 5) x && inIncreasingSerie (figureNum 3) x

答案 1 :(得分:1)

以下是对您提出的问题的简单直接回答:

*Main> take 1 $ filter (\(x,y,z) -> (x == y) && (y == z)) $ zip3 [1,2,3] [4,2,6] [8,2,9]
[(2,2,2)]

当然,yairchu的回答在实际解决欧拉问题时可能更有用:)

答案 2 :(得分:0)

至少有几种方法可以做到这一点。

您可以查看第一项,并将其余项目与之比较:

Prelude> (\x -> all (== (head x)) $ tail x) [ [1,2,3], [1,2,3], [4,5,6] ]
False
Prelude> (\x -> all (== (head x)) $ tail x) [ [1,2,3], [1,2,3], [1,2,3] ]
True

或者您可以创建一个类似于前一个的显式递归函数:

-- test.hs
f [] = True
f (x:xs) = f' x xs where
    f' orig (y:ys) = if orig == y then f' orig ys else False
    f' _ [] = True


Prelude> :l test.hs
[1 of 1] Compiling Main             ( test.hs, interpreted )
Ok, modules loaded: Main.
*Main> f [ [1,2,3], [1,2,3], [1,2,3] ]
True
*Main> f [ [1,2,3], [1,2,3], [4,5,6] ]
False

您也可以执行takeWhile并比较返回列表的长度,但这既不高效也不典型Haskell。

<小时/> 糟糕,只是看到根本没有回答你的问题。将此标记为CW,以防任何人通过Google绊倒您的问题。

答案 3 :(得分:0)

最简单的方法是稍微重新指定问题

而不是处理三个列表(注意删除多余的n参数):

hexag = [ n*(2*n-1) | n <- [40755..]]
penta = [ n*(3*n-1)/2 | n <- [40755..]] 
trian = [ n*(n+1)/2   | n <- [40755..]]

例如,您可以生成一个列表:

matches :: [Int]
matches = matches' 40755


matches' :: Int -> [Int]
matches' n 
    | hex == pen && pen == tri = n : matches (n + 1)
    | otherwise                =     matches (n + 1) where
   hex = n*(2*n-1)
   pen = n*(3*n-1)/2
   tri = n*(n+1)/2

现在,您可以尝试通过注意重复来优化此性能。例如,在(n + 1)处计算下一个匹配时:

(n+1)*(n+2)/2 - n*(n+1)/2 = n + 1

所以你可以将(n + 1)添加到前一个tri以获得新的tri值。

类似的代数简化可以应用于其他两个函数,并且您可以将所有这些函数用于累积参数到函数匹配'。

也就是说,有更有效的方法来解决这个问题。