如何使用哈希值修改数组的值?

时间:2015-03-08 03:55:26

标签: ruby

我正在构建一个基本转换器。到目前为止,这是我的代码:

def num_to_s(num, base)
remainders = [num]

while base <= num   
 num /= base  #divide initial value of num
 remainders << num       #shovel results into array to map over for remainders
end

return remainders.map{|i| result = i % base}.reverse.to_s   #map for remainders and shovel to new array

puts num_to_s(40002, 16)

end

现在是时候考虑字母替换数字的超过10的基数。 (练习的)指示建议使用哈希。这是我的哈希:

conversion = {10 => 'A', 11 => 'B', 12 => 'C', 13 => 'D', 14 => 'E', 15 => 'F',}

现在的问题是,如何将其合并以便修改数组?我试过了:

return remainders.map{|i| result = i % base}.map{|i| [i, i]}.flatten.merge(conversion).reverse.to_s

尝试将'remainingders'数组转换为哈希并合并它们,以便'conversion'中的值覆盖'remainingders'中的值,但是我得到'奇怪的Hash列表'错误。经过一些研究后,似乎是由于我正在运行的Ruby版本(1.8.7),并且无法更新。我也尝试将数组转换为返回之外的哈希:

Hashes = Hash[remainders.each {|i, i| [i, i]}].merge(conversion)

我得到一个'动态常量赋值'错误。我尝试了很多不同的方法来做到这一点......哈希甚至可以用来修改数组吗?我也在想也许我可以通过在枚举器中使用条件语句来实现这一点(每个?map?)但是却无法完成这项工作。 CAN可以在枚举器中放置一个条件吗?

3 个答案:

答案 0 :(得分:1)

除了问题,您可以使用Fixnum#to_s(base)来转换基础。

255.to_s(16) # 'ff'

答案 1 :(得分:1)

我会做一个

def get_symbol_in_base(blah)
  if blah < 10
    return blah
  else
    return (blah - 10 + 65).chr
  end
end

然后执行以下操作:

remainders << get_symbol_in_base(num)
return remainders.reverse.to_s

答案 2 :(得分:1)

是的,您可以使用哈希:

def digit_hash(base)
  digit = {}      
  (0...[10,base].min).each { |i| digit.update({ i=>i.to_s }) }
  if base > 10
    s = ('A'.ord-1).chr
    (10...base).each { |i| digit.update({ i=>s=s.next }) }
  end
  digit
end

digit_hash(40) 
  #=> { 0=>"0",   1=>"1",   2=>"2",   3=>"3",  4=>"4",
  #     5=>"5",   6=>"6",   7=>"7",   8=>"8",  9=>"9",
  #    10=>"A",  11=>"B",  12=>"C",      ..., 34=>"Y", 35=>"Z",
  #    36=>"AA", 37=>"AB", 38=>"AC", 39=>"AD" }

在&#39; Z&#39;之后显示数字时出现问题。例如,假设基数为65.那么人们就不知道&#34; ABC&#34;是10-11-12,37-12或10-64。这个细节我们不用担心。

对于多样性,我已经完成了从高到低的基本转换,就像基地10的纸和笔一样:

def num_to_s(num, base)
  digit = digit_hash(base)
  str = ''
  fac = base**((0..Float::INFINITY).find { |i| base**i > num } - 1)
  until fac.zero?
    d = num/fac
    str << digit[d] 
    num -= d*fac
    fac /= base                   
  end
  str
end

让我们试一试:

num_to_s(134562,10) #=> "134562" 
num_to_s(134562, 2) #=> "100000110110100010" 
num_to_s(134562, 8) #=> "406642" 
num_to_s(134562,16) #=> "20DA2" 
num_to_s(134562,36) #=> "2VTU" 

让我们检查最后一个:

digit_inv = digit_hash(36).invert
digit_inv["2"] #=>  2 
digit_inv["V"] #=> 31 
digit_inv["T"] #=> 29 
digit_inv["U"] #=> 30 

所以

36*36*36*digit_inv["2"] + 36*36*digit_inv["V"] +
  36*digit_inv["T"] + digit_inv["U"] 
  #=> 36*36*36*2 + 36*36*31 + 36*29 + 30
  #=> 134562

表达式:

(0..Float::INFINITY).find { |i| base**i > num }

计算i的最小整数base**i > num。例如,假设

base =    10
num  = 12345

然后发现i等于510**5 = 100_000)。然后我们将base提高到这个数字,减去一个得到初始因子:

fac = base**(5-1) #=> 10000

然后第一个(基数为10)的数字是

d = num/fac   #=> 1

剩下的是

num -= d*fac #=> 12345 - 1*10000 => 2345

,下一个数字的因素是:

fac /= base  #=> 10000/10 => 1000

我从最初的答案做了几处修改,以1.87-friedly(我删除了Enumerator#with_objectInteger#times),但我还没有用1.8.7进行测试,因为我没有安装该版本。如果有任何问题,请告诉我。