首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >我不明白这个从-256大写到十进制的红宝石代码。

我不明白这个从-256大写到十进制的红宝石代码。
EN

Stack Overflow用户
提问于 2019-07-30 05:01:01
回答 3查看 181关注 0票数 0

吉特卜的代码

代码的目标很简单:将base-256字节字符串转换为base-10。

代码语言:javascript
复制
def debase256(string)
  string.reverse.bytes.inject([0, 1]) do |(sum, pow), byte|
    [pow * byte.ord, pow * 256]
  end.first
end

我试着读它,但我只读了“reverse.bytes”

我无法想象在这个过程中字节是如何移动和变化的。

我只需要一个例子来解释这一点。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2019-07-30 06:33:12

密码是错的。它没有计算总数。块中的第一个数组项应该是sum + pow * byte.ord。而且,byte.ord没有任何意义,因为Integer#ord只会返回自己。

因此,正确的代码是:

代码语言:javascript
复制
def debase256(string)
  string.reverse.bytes.inject([0, 1]) do |(sum, pow), byte|
    [sum + pow * byte, pow * 256]
  end.first
end

不过,这段代码有点难理解。也许下面的代码(没有方法声明)有助于您更好地理解它:

代码语言:javascript
复制
string.reverse.bytes.map.with_index do |byte, i|
  byte * 256**i
end.sum

让我们看一个使用字符串"Test"的示例

代码语言:javascript
复制
string = "Test"

首先,我们将其逆转:

代码语言:javascript
复制
string.reverse # => "tseT"

然后我们得到字节:

代码语言:javascript
复制
string.reverse.bytes # => [116, 115, 101, 84]

现在我们要从这个256基数构造一个10基数。为此,我们将每个时隙索引i乘以256^i,其中i从0开始。

代码语言:javascript
复制
"Test".reverse.bytes.map.with_index { |byte, i| byte * 256**i }
# => [116 * 256^0, 115 * 256^1, 101 * 256^2, 84 * 256^3]
# => [116 * 1, 115 * 256, 101 * 65536, 84 * 16777216]
# => [116, 29440, 6619136, 1409286144]

最后,我们取和,这是它的基10表示。

代码语言:javascript
复制
"Test".reverse.bytes.map.with_index { |byte, i| byte * 256**i }.sum
# => 1415934836

为了理解我们正在做的事情,让我们尝试使用10到10基的转换。假设我们有一个基数为10的数字,例如1234。我们得到这个数字:

代码语言:javascript
复制
1234.digits
# => [4, 3, 2, 1]

注意#digits是如何返回倒转的数字的。

现在,在基数10中,每个时隙i都需要乘以10^i (与以上基本256个情况下的256^i相比):

代码语言:javascript
复制
1234.digits.map.with_index { |byte, i| byte * 10**i }
# => [4 * 10^0, 3 * 10^1, 2 * 10^2, 1 * 10^3]
# => [4 * 1, 3 * 10, 2 * 100, 1 * 1000]
# => [4, 30, 200, 1000]

之和它将给我们的基数10:

代码语言:javascript
复制
1234.digits.map.with_index { |byte, i| byte * 10**i }.sum
# => 1234

因此,唯一的区别是基础,逻辑是一样的。

您可能遇到的另一个示例是十六进制中的RGB颜色值,例如#ac4fbe。对于红色、绿色和蓝色,我们的值从0到255不等,用十六进制编码。十六进制是16基的一个很好的词。通常,十六进制数字表示为0 to 9a表示为f

代码语言:javascript
复制
0 1 2 3 4 5 6 7 8 9  a  b  c  d  e  f
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15

知道了这一点之后,让我们看一下颜色#ac4fbe的红色值,它由第一个字符ac表示。

这里的逻辑和上面的一样。相反,这给了我们ca。如果我们得到每个字符的基数10个,那就是[12, 10]。让我们用16^i将每个插槽相乘

代码语言:javascript
复制
[12 * 16^0, 10 * 16^1] == [12 * 1, 10 * 16] == [12, 160]

12 + 160172,它是红色成分在颜色中的值。

同样,这与其他例子中的逻辑是一样的。

我希望这些例子能帮助你理解这是如何工作的。作为练习,尝试将这个二进制数字(即基数2)转换为基数10:

代码语言:javascript
复制
101010

请记住,这些插槽:

代码语言:javascript
复制
digits: 1 0 1 0 1 0
slot i: 5 4 3 2 1 0

(提示:这是对生命、宇宙和一切终极问题的答案。)

票数 2
EN

Stack Overflow用户

发布于 2019-07-30 06:17:52

inject执行一个循环,其中“累积变量”(也称为“备注对象”)是一个二元数组,最初被设置为[0,1]。在每次迭代时,这个对象作为[sum, pow]传递给循环主体,以及输入数组中的下一个元素,后者存储在byte中。循环体计算要在下一次迭代中使用的更新的备注对象。inject的结果是备注对象的最终值。

您可以跟踪正在发生的事情,将循环体替换为

代码语言:javascript
复制
[pow * byte.ord, pow * 256].tap do
  |new_sum, new_pow|
  puts "Working on byte #{byte.inspect}"
  puts "old sum and pow : #{sum},#{pow}" 
  puts "new sum and pow : #{new_sum}, #{new_pow}"
end
票数 0
EN

Stack Overflow用户

发布于 2019-07-30 06:23:34

假设字符串是"AB“( ASCII代码为65和66):

string.reverse.bytes给你[66,65]

[66,65].inject([0,1])通过数组[66,65]并将结果数组[0,1]带到每次迭代中。循环需要返回修改过的数组版本,并将其传递到下一次迭代。

示例1:

代码语言:javascript
复制
[66,65].inject([0,1]) do |(sum, pow), byte|
  puts "sum: #{sum} pow: #{pow} byte: #{byte}"
  [sum, pow] # this gets passed to the next round
 end

这一产出如下:

代码语言:javascript
复制
sum: 0 pow: 1 byte: 66
sum: 0 pow: 1 byte: 65

有一个不同类型的“备忘录”数组:

代码语言:javascript
复制
memo = []
[66,65].inject(memo) do |memo, byte|
  memo << "byte is #{byte}"
  memo
 end
 puts memo.inspect

这一产出如下:

代码语言:javascript
复制
["byte is 66", "byte is 65"]

因此,inject类似于each,但是给定的“备忘录”对象将从每一轮传递到下一轮。

该方法使用备忘录保存两个值:下一个字节的和。

将调试输出添加到原始方法:

代码语言:javascript
复制
def debase256(string)
  string.reverse.bytes.inject([0, 1]) do |(sum, pow), byte|
    puts "sum: #{sum} pow: #{pow} byte: #{byte}"
    [pow * byte.ord, pow * 256]
  end.first
end

使用debase256("ABC")输出运行此操作:

代码语言:javascript
复制
sum: 0 pow: 1 byte: 67
sum: 67 pow: 256 byte: 66
sum: 16896 pow: 65536 byte: 65

因此,我们看到第一轮|(sum, pow), byte|的输入是(0, 1), 67

pow * byte.ord1 * 67 = 67

pow * 2561 * 256 = 256

所以,第二轮的|(sum, pow), byte|是:(67, 256), 66

pow * byte.ord256 * 66 = 16896

pow * 256256 * 256 = 65536

所以最后一轮的|(sum, pow), byte|是:(16896, 65536), 65

pow * byte.ord65536 * 65 = 4259840

pow * 25665536 * 256 = 16777216

因为这是最后一轮,块将返回备忘录,即[4259840, 16777216]。第一个元素包含所需的结果,而最后一个元素不再需要,因此调用.first来获取和。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/57264579

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档