代码的目标很简单:将base-256字节字符串转换为base-10。
def debase256(string)
string.reverse.bytes.inject([0, 1]) do |(sum, pow), byte|
[pow * byte.ord, pow * 256]
end.first
end我试着读它,但我只读了“reverse.bytes”
我无法想象在这个过程中字节是如何移动和变化的。
我只需要一个例子来解释这一点。
发布于 2019-07-30 06:33:12
密码是错的。它没有计算总数。块中的第一个数组项应该是sum + pow * byte.ord。而且,byte.ord没有任何意义,因为Integer#ord只会返回自己。
因此,正确的代码是:
def debase256(string)
string.reverse.bytes.inject([0, 1]) do |(sum, pow), byte|
[sum + pow * byte, pow * 256]
end.first
end不过,这段代码有点难理解。也许下面的代码(没有方法声明)有助于您更好地理解它:
string.reverse.bytes.map.with_index do |byte, i|
byte * 256**i
end.sum让我们看一个使用字符串"Test"的示例
string = "Test"首先,我们将其逆转:
string.reverse # => "tseT"然后我们得到字节:
string.reverse.bytes # => [116, 115, 101, 84]现在我们要从这个256基数构造一个10基数。为此,我们将每个时隙索引i乘以256^i,其中i从0开始。
"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表示。
"Test".reverse.bytes.map.with_index { |byte, i| byte * 256**i }.sum
# => 1415934836为了理解我们正在做的事情,让我们尝试使用10到10基的转换。假设我们有一个基数为10的数字,例如1234。我们得到这个数字:
1234.digits
# => [4, 3, 2, 1]注意#digits是如何返回倒转的数字的。
现在,在基数10中,每个时隙i都需要乘以10^i (与以上基本256个情况下的256^i相比):
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:
1234.digits.map.with_index { |byte, i| byte * 10**i }.sum
# => 1234因此,唯一的区别是基础,逻辑是一样的。
您可能遇到的另一个示例是十六进制中的RGB颜色值,例如#ac4fbe。对于红色、绿色和蓝色,我们的值从0到255不等,用十六进制编码。十六进制是16基的一个很好的词。通常,十六进制数字表示为0 to 9,a表示为f。
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将每个插槽相乘
[12 * 16^0, 10 * 16^1] == [12 * 1, 10 * 16] == [12, 160]和12 + 160是172,它是红色成分在颜色中的值。
同样,这与其他例子中的逻辑是一样的。
我希望这些例子能帮助你理解这是如何工作的。作为练习,尝试将这个二进制数字(即基数2)转换为基数10:
101010请记住,这些插槽:
digits: 1 0 1 0 1 0
slot i: 5 4 3 2 1 0(提示:这是对生命、宇宙和一切终极问题的答案。)
发布于 2019-07-30 06:17:52
inject执行一个循环,其中“累积变量”(也称为“备注对象”)是一个二元数组,最初被设置为[0,1]。在每次迭代时,这个对象作为[sum, pow]传递给循环主体,以及输入数组中的下一个元素,后者存储在byte中。循环体计算要在下一次迭代中使用的更新的备注对象。inject的结果是备注对象的最终值。
您可以跟踪正在发生的事情,将循环体替换为
[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发布于 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:
[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这一产出如下:
sum: 0 pow: 1 byte: 66
sum: 0 pow: 1 byte: 65有一个不同类型的“备忘录”数组:
memo = []
[66,65].inject(memo) do |memo, byte|
memo << "byte is #{byte}"
memo
end
puts memo.inspect这一产出如下:
["byte is 66", "byte is 65"]因此,inject类似于each,但是给定的“备忘录”对象将从每一轮传递到下一轮。
该方法使用备忘录保存两个值:下一个字节的和。
将调试输出添加到原始方法:
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")输出运行此操作:
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.ord是1 * 67 = 67
pow * 256是1 * 256 = 256。
所以,第二轮的|(sum, pow), byte|是:(67, 256), 66。
pow * byte.ord是256 * 66 = 16896。
pow * 256是256 * 256 = 65536。
所以最后一轮的|(sum, pow), byte|是:(16896, 65536), 65
pow * byte.ord是65536 * 65 = 4259840。
pow * 256是65536 * 256 = 16777216。
因为这是最后一轮,块将返回备忘录,即[4259840, 16777216]。第一个元素包含所需的结果,而最后一个元素不再需要,因此调用.first来获取和。
https://stackoverflow.com/questions/57264579
复制相似问题