List 是否从[1..]的映射中排除计算结果?
我目前正在做一个计算友好对的程序(欧拉项目)。我已经找到了解决方案,但是我注意到我的程序中的一个缺陷是它计算集合[1..]的所有数字,不管我们是否已经找到了一对数字 i、 e.如果当前评估的220和284是它的一对,但是当map函数到达284时,它不应该再次评估它List 是否从[1..]的映射中排除计算结果?,list,haskell,infinite,fold,List,Haskell,Infinite,Fold,我目前正在做一个计算友好对的程序(欧拉项目)。我已经找到了解决方案,但是我注意到我的程序中的一个缺陷是它计算集合[1..]的所有数字,不管我们是否已经找到了一对数字 i、 e.如果当前评估的220和284是它的一对,但是当map函数到达284时,它不应该再次评估它 import Data.List properDivisors :: (Integral a) => a -> [a] properDivisors n = [x | x <- [1..n `div` 2],
import Data.List
properDivisors :: (Integral a) => a -> [a]
properDivisors n = [x | x <- [1..n `div` 2],
n `mod` x == 0 ]
amicablePairOf :: (Integral a) => a -> Maybe a
amicablePairOf a
| a == b = Nothing
| a == dOf b = Just b
| otherwise = Nothing
where dOf x = sum (properDivisors x)
b = dOf a
getAmicablePair :: (Integral a) => a -> [a]
getAmicablePair a = case amicablePairOf a of
Just b -> [a,b]
Nothing -> []
amicables = foldr (++) [] ams
where ams = map getAmicablePair [1..]
返回:
[220,284,284,220]
我对Haskell和函数式编程相当陌生,所以如果这是一个显而易见的解决方案,请原谅。也许对
getAmicablePair
稍作修改会有帮助吗
getAmicablePair :: (Integral a) => a -> [a]
getAmicablePair a = case amicablePairOf a of
Just b -> if a < b then [a,b] else []
Nothing -> []
getAmicablePair::(积分a)=>a->[a]
Getanicablepair a=案例友好对a
只要b->如果a[]
。。。所以你只需要得到第一个元素较小的配对,你的问题是,你要通过输出两个友好的数字来保证工作的安全。但事实上,你不太安全,因为你的函数仍然计算这两个数,不管它们是否友好。为什么不这样做:
import Data.List
divSum :: (Integral a) => a -> [a]
divSum n = sum (filter (\a -> a `mod` n == 0) [1..n `div` 2])
isAmicable :: (Integral a) => a -> Bool
isAmicable a = a /= b && a == c where
b = divSum a
c = divSum b
amicables = filter isAmicable [1..]
很好的解决方案,但是问题是程序仍然会对这对进行两次评估,只是不会在第二次显示它。我知道如何使用“nub”函数从Data.List中删除重复项,但是我想通过只对一对进行一次计算来提高效率。@Axilus-你说得对。。。但是您不能使用
map
,因为map
不能引用早期的计算。@Axilus:我怀疑您只计算一次就可以提高效率。首先,您必须在已经生成的所有友好数字列表中进行查找,这样您的函数就不再在常量空间中运行(假设您立即使用结果)。此外,所有数字中只有一小部分是友好的,所以你也不会赢得任何东西。这种友好关系是对称的吗?如果是,Fuzzxxl的解决方案是好的。如果不是。。。那么我怀疑避免这些计算是否明智。@phynfo:amicable意味着两个数字有一种特殊的关系,即它们的除数之和等于另一个数字。所以它确实是对称的。1000000000以下的友好数字只有1427个,因此不值得为这么小的一部分避免计算。一个好的优化方法是检查,如果数字不足,那么总数是否已经包含在列表中。这将有一段时间是安全的,因为人们可以在大约50%的数字中避免第二次求和。Don Knuth有句名言:»过早的选择是万恶之源。«通常,最好的方法是以直接的方式编写代码,然后进行分析。如果结果不令人满意,试着对代码进行优化。最好的方法是以一种简单的方式编写代码,然后在需要时进行概要分析。如果你得到了答案,谁在乎过去花了多长时间
import Data.List
divSum :: (Integral a) => a -> [a]
divSum n = sum (filter (\a -> a `mod` n == 0) [1..n `div` 2])
isAmicable :: (Integral a) => a -> Bool
isAmicable a = a /= b && a == c where
b = divSum a
c = divSum b
amicables = filter isAmicable [1..]