【问题标题】:Comparing 3 output lists in haskell比较haskell中的3个输出列表
【发布时间】:2009-08-13 09:08:36
【问题描述】:

我正在做另一个Project Euler 问题,我需要找到这3个列表的结果何时相等(我们第一次给定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 解决方案。

【问题讨论】:

标签: haskell


【解决方案1】:
  • 你的函数很奇怪。他们得到 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

【讨论】:

  • 记住,我还在学习 Haskell.... 我想解决这个问题的方法是只计算数字,然后只显示结果数字都相等时的结果。我还没有学到任何关于 monad 的知识。
  • @Jonno_FTW:很酷。请注意,除了“main”之外,这里没有使用 monad。
【解决方案2】:

下面是对您所提问题的简单直接回答:

*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 的回答在实际解决欧拉问题时可能更有用:)

【讨论】:

    【解决方案3】:

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

    您可以查看第一个项目,然后将其余项目与它进行比较:

    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 偶然发现您的问题。

    【讨论】:

      【解决方案4】:

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

      而不是处理三个列表(注意删除多余的 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 值。

      类似的代数化简可以应用到其他两个函数,你可以将它们都带入到函数匹配的累加参数中。

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

      【讨论】:

        猜你喜欢
        • 2016-04-01
        • 2011-11-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-02-21
        相关资源
        最近更新 更多