我是否正确理解了此代码的工作原理?

时间:2016-09-19 10:37:35

标签: ruby

基本上,我正在尝试用Ruby解决第一个Project Euler问题。如果您想知道参考,Here就是问题所在。我尝试从头开始自己解决这个问题,但这并不是很好,所以我决定走另一条路:在网上找别人的解决方案,把它分开,给自己解释一下,试着看看我是否可以建立如果我能确切地知道他们的代码在做什么,我自己独特的解决方案。根据我的经验,这始终是我学习的最佳方式。这是我找到的解决方案,并决定分开:

puts (1..1000).select{ |n| n % 3 == 0 || n % 5 == 0 }.reduce(:+)

我找到了这个解决方案here。基本上,我想要的是“告诉我问题的答案”,而不是“阅读我的笔记并告诉我什么是对的,什么是错的,并逐步为我解决问题。”再说一次,如果这不是SO的正确使用,我很抱歉!我不知道还能问什么,如果不是我应该问的地方,我会删除我的问题。 :)这是我对代码的注释以及我如何向自己解释:

  
      
  • 它将数字1-999(“范围”)放下

  •   
  • 然后用“.select”选择它。大括号几乎像css一样使用,但更类似于Ruby中的“do”和“end”(“do”启动一个命令,“end”结束它)。 “do / end”和大括号之间的区别在于大括号适用于可以放入一行而不需要多行的命令。

  •   
  • | | =管道定义“块”,而“n”代表数字/数字。它是一个内部有变量的块。这意味着| n |要求命令从所选范围中调出一个数字。
  •   
  • “n%3”查找3的倍数; == 0寻找答案(?)。重复五次。
  •   
  • 然后“.reduce(:+)”通过将所有数字加在一起来缩短命令。
  •   

我对自己的理解有点自信,但如果有什么不对(术语,一般概念等),如果你让我知道并解释它,我会很高兴!我真的只是想学习并把事情分开,向自己解释它们通常对我有所帮助。

4 个答案:

答案 0 :(得分:1)

简单地说,该语句打印的结果是取1到1000之间的每个数字,可以被3或5整除,并返回集合的总和(234168)。

puts只是一个简单的打印命令,它写入输出缓冲区(默认为STDio)。 puts在每个参数后添加换行符。 print没有。

  

.select
  返回一个数组,其中包含给定的枚举的所有元素   block返回一个真值。

所以是的,在这种情况下,它将允许任何可被3或5整除的值

irb(main):005:0> (1..10).select{ |n| n % 3 == 0 || n % 5 == 0 }
=> [3, 5, 6, 9, 10]
  

花括号几乎像css一样使用,但更类似于   Ruby中的“do”和“end”

我不太确定CSS的相似性,因为CSS只是一种声明性语言。

大括号和do ... end都是Rubys声明块的方式 - 这只是匿名函数。编译器实际上并不关心,并允许您使用括号编写多行语句。但是,有一个强有力的社区公约,do ... end应该优先考虑更长的陈述。

在使用Underscore库的Javascript中,它看起来像这样:

console.log( 
  _.filter( 
    _.range(1, 10), function(n){ n % 3 == 0 || n % 5 == 0 } 
  )
);
  

reduce(sym) → obj

     

通过应用二进制操作组合枚举的所有元素,   由命名方法或运算符的块或符号指定。

因此,reduce会从select中获取数组,并将元素添加到一起。 :+实际上是我们在“备忘录”上调用的方法。

[1,2,3].reduce(:+)

也可以写成:

[1,2,3].reduce { |memo, obj| memo.send(:+, obj) }
# or
[1,2,3].reduce { |memo, obj| memo.+(obj) }

这可能看起来很奇怪,但请记住,在Ruby中,一切都是对象。 +实际上是FixNum类的方法,而不是其他语言中的关键字。

Ruby中的1 + 2实际上是1.+(2)的语法糖。

答案 1 :(得分:1)

  

它将数字1-999(“范围”)放下

我不确定“把数字放下来”应该是什么意思。

puts将给定对象(即其参数)写入默认为终端的standard output。在您的示例中,它输出给定表达式的结果。但要做到这一点,必须对表达式进行评估。

1..1000创建一个Range,一个表示从11000的区间的对象。范围包含在括号中,因为1..1000.select会尝试调用1000.select,从而导致错误。 (1..1000).select按预期工作。

  

然后用“.select”选择它。

select是一种来自Enumerable的方法 - 一个为ArrayHashRange等集合提供功能的模块。 select不“选择范围”,它根据条件从范围中选择元素。把它想象成一个过滤器。

  

花括号几乎像css一样使用......

嗯,{ ... }在CSS和Ruby中都被称为“块”。

但是在CSS中,这些块用于对应用于选择器的多个声明进行分组。

在Ruby中,块参数向方法发送closure。因此,不是将静态值传递给select,而是传递一个函数。 select稍后可以调用此函数(即块)。

  

...但更类似于Ruby中的“do”和“end”

对于块,您可以使用do ... end而不是{ ... },反之亦然,但您可能需要添加括号或分号才能获得相同的结果。

  

(“做”开始一个命令,“结束”结束它)

阻止,而不是命令。

  

“do / end”和花括号之间的区别在于大括号适用于可以放入一行而不需要多行的命令。

这是一个惯例(也有other conventions)。实际差异是优先级,请参阅block arguments的示例。

  

| | =管道定义“块”,而“n”代表数字/数字。它是一个内部有变量的块。

{ ... }定义了一个块。 | ... |保存传递给块的参数。 n就是这样的论点。参数个数由调用块的方法指定(在本例中为select),但您可以选择参数的名称。

  

这意味着| n |要求命令从所选范围中调出一个数字。

该块是被动的,它不会要求任何东西。而且没有“选定的范围”。 select是一种方法。它将范围内的每个数字传递给给定的块。在该区块内,可以通过n引用此号码。

即使select不知道元素,也必须调用Range#each才能遍历集合。

  

“n%3”查找3的倍数;

n % 3返回模数,即将 n 除以3的余数:

1 % 3 #=> 1     1 divided by 3 = 0, remainder 1
2 % 3 #=> 2     2 divided by 3 = 0, remainder 2
3 % 3 #=> 0     3 divided by 3 = 1, remainder 0
4 % 3 #=> 1     4 divided by 3 = 1, remainder 1
  

== 0寻找答案(?)

它会将n % 3的结果与0进行比较。换句话说,如果n % 3 == 0可以被true整除,n会返回3,否则会false

  

重复五次。

其中还有一个||,它是逻辑 OR

n % 3 == 0 || n % 5 == 0转换为“n可以被3整除,或者n可以被5”整除。

  

然后“.reduce(:+)”通过将所有数字相加来缩短命令。

首先,select返回一个新数组。更明确地,select返回一个新数组,其中包含1..1000的所有元素,块返回true

reduce然后将:+表示的操作应用于所有这些元素。

[1, 2, 3].reduce(:+)相当于1 + 2 + 3

答案 2 :(得分:0)

{}花括号的优先级高于 do..end。

您也可以将{}用于多行。但是 do..end 不能写在一行中。

表示.select,它返回一个新数组。

>array = []
>array = (1..1000).select{ |n| n % 3 == 0 || n % 5 == 0 }
>array

将返回数组,其数字可以除以3或5,介于1到1000之间。

答案 3 :(得分:0)

只是从你的回答中对这一点超级明确:

  

" n%3"寻找3的倍数; == 0寻找答案(?)。重复   为五。

它没有"重复"这里,这个符号" ||"代表"逻辑OR。"这意味着这一行:

{ |n| n % 3 == 0 || n % 5 == 0 }

查找所有数字n,使得n是3的倍数或者n是5的倍数。

您可以在这里很好地理解Ruby逻辑运算符:

Ruby the Hard Way ex 27