beo*_*ver 14 ruby python haskell list-comprehension
我已经开始将项目Euler站点作为一种学习Haskell的方法,并改进我的Python和Ruby.我认为Haskell和Python版本都可以,但我确信Ruby必须有一个更简洁的方法.
这不是关于如何使一种语言看起来像另一种语言.
这是问题1:
问:添加1000以下的所有自然数,即3或5的倍数.
哈斯克尔:
sum [ x | x <- [1..999], mod x 3 == 0 || mod x 5 == 0 ]
Run Code Online (Sandbox Code Playgroud)
蟒蛇:
sum ( [ x for x in range(1,1000) if x % 3 == 0 or x % 5 == 0 ] )
Run Code Online (Sandbox Code Playgroud)
红宝石:
(1..999) . map {|x| x if x % 3 == 0 || x % 5 == 0 } . compact . inject(:+)
Run Code Online (Sandbox Code Playgroud)
他们都给出了相同的答案.
好的,所以Python可以成为:
sum ( x for x in range(1,1000) if x % 3 == 0 or x % 5 == 0 )
Run Code Online (Sandbox Code Playgroud)
它现在是一个生成器(因为我们没有存储列表是一件好事)
但更有趣的是:
sum( set(range(0,1000,3)) | set(range(0,1000,5)) )
Run Code Online (Sandbox Code Playgroud)
出于某种原因,我再次看到这个,并尝试了一个总和方法,这应该是恒定的时间.在Python 3中:
def step_sum(mn,mx,step):
amax = mx - (mx - mn) % step
return (mn + amax) * ((1 + ((amax - mn) / step)) / 2)
step_sum(3,999,3) + step_sum(5,999,5) - step_sum(15,999,15)
Run Code Online (Sandbox Code Playgroud)
Ruby可以成为:
(1..999) . select {|x| x % 3 == 0 || x % 5 == 0} . inject(:+)
Run Code Online (Sandbox Code Playgroud)
要么
(1..999) . select {|x| x % 3 == 0 or x % 5 == 0} . reduce(:+)
Run Code Online (Sandbox Code Playgroud)
我假设不同map,select不产生'nul',因此没有必要打电话compact.不错.
Haskell也可以是:
let ƒ n = sum [0,n..999] in ƒ 3 + ƒ 5 - ƒ 15
Run Code Online (Sandbox Code Playgroud)
或者更清楚:
let ƒ n = sum [ 0 , n .. 999 ] in ƒ 3 + ƒ 5 - ƒ (lcm 3 5)
Run Code Online (Sandbox Code Playgroud)
作为一个功能,让我们自己提供两个数字:
ƒ :: (Integral a) => a -> a -> a
ƒ x y = let ƒ n = sum [0,n..999] in ƒ x + ƒ y - ƒ (lcm x y)
Run Code Online (Sandbox Code Playgroud)
对于Haskell,我喜欢
let s n = sum [0,n..999] in s 3 + s 5 - s 15
Run Code Online (Sandbox Code Playgroud)
要么
sum $ filter ((>1).(gcd 15)) [0..999]
Run Code Online (Sandbox Code Playgroud)
为了好玩Rube-Goldberg版本:
import Data.Bits
sum $ zipWith (*) [1..999] $ zipWith (.|.) (cycle [0,0,1]) (cycle [0,0,0,0,1])
Run Code Online (Sandbox Code Playgroud)
好的,解释时间.
第一个版本定义了一个小函数s,它将n的所有倍数加总到999.如果我们将所有3的倍数和5的所有倍数相加,我们将所有的15的倍数包括在内(每个列表中一次),因此我们需要减去它们一次.
第二个版本使用3和5是素数的事实.如果数字包含因子3和5中的一个或两个,则该数字和15的gcd将是3,5或15,因此在每种情况下gcd将大于1.对于没有共同因子15的其他数字,gcd变为1.这是一个很好的技巧,可以一步测试两个条件.但要小心,它不适用于任意数字,例如,当我们有4和9时,测试gdc x 36 > 1将不起作用gcd 6 36 == 6,但是既不是mod 6 4 == 0也不是mod 6 9 == 0.
第三个版本很有趣.cycle一遍又一遍地重复列表.cycle [0,0,1]对3的"可分性模式"进行编码,并cycle [0,0,0,0,1]为5进行相同的编码.然后我们将"或"两个列表一起使用zipWith,这给了我们[0,0,1,0,1,1,0,0,1,1,0,1...].现在我们zipWith再次使用它与实际数字相乘,得到[0,0,3,0,5,6,0,0,9,10,0,12...].然后我们就加起来吧.
了解不同的方法来做同样的事情可能会浪费其他语言,但对于Haskell来说,它是必不可少的.你需要发现模式,拾取技巧和习语,并且玩弄很多,以获得有效使用这种语言的精神灵活性.项目欧拉问题等挑战是一个很好的机会.
| 归档时间: |
|
| 查看次数: |
2797 次 |
| 最近记录: |