2015-03-08 3 views
0

Я строию базовый конвертер. Вот мой код:Как использовать хэш для изменения значений массива?

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 

В попытке преобразовать массив «остатков» в хэш и объединить их, чтобы значения в «преобразовании» переопределить те, в «остатках», но я получаю «странный список для Hash ". После некоторых исследований, похоже, из-за версии Ruby (1.8.7) я запускаю и не смог обновить. Я также попытался преобразование массива в хэш за пределами возвращения:

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

и я получаю ошибку «динамического постоянная назначения». Я попробовал кучу разных способов сделать это ... Может ли хэш даже использоваться для изменения массива? Я тоже думал, может быть, я мог бы это сделать, используя условный оператор в перечислении (каждая? Карта?), Но не смог выполнить эту работу. МОЖЕТ ЛИ УСТАНОВИТЬ условие в перечислителе?

+0

Я должен спросить: почему вы используете восьмилетнюю версию Ruby? –

+0

он пришел с моим imac, которому около 6 лет, и по-прежнему OS 10.6.8. Я попытался обновить свой рубин сегодня, и он не сработал, где-то в потоке ошибок, у меня сложилось впечатление, что он говорил мне, что мне нужно обновить моя операционная система, которая является испытанием для себя, и я стараюсь избегать. Я слышал ужасные вещи о Йосемити. Но если я ДОЛЖЕН, я это сделаю. – HolyMoly

+1

Вам действительно нужно обновить, по крайней мере, до Mavericks, а затем установить [RVM] (https://rvm.io) («Ruby Version Manager») и использовать его для установки и переключения между версиями Ruby. RVM немного запутывается, но просто следуйте пошаговым инструкциям, и все будет в порядке. Я предлагаю вам использовать последнюю версию Ruby (в настоящее время 2.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" } 

Там является проблема при отображении цифр после «Z». Предположим, например, что основание было 65. Тогда не было бы знать, было ли «ABC» 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 } 

вычисляет наименьшее целое число такое, что ibase**i > num.Предположим, например,

base = 10 
num = 12345 

затем i оказывается равной 5 (10**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_object и Integer#times), но я не тестировал его с 1.8.7, так как у меня нет установленной версии. Дайте мне знать, если возникнут проблемы.

+0

@ Кэри, я должен признать, что я действительно новичок в Ruby, и на данный момент много моего решения над моей головой. Я еще не выучил много методов, которые вы использовали (но google - мой друг) Это сложная вещь для newb на форуме, полном pro's ... lol..I пытался запустить его, и я получаю ошибки - возможно, это тоже вопрос 1.8.7. Хотя я не совсем понимаю это сейчас, я собираюсь разобрать его, пока не сделаю;) Спасибо! Я многому учу от вас, ребята! – HolyMoly

+1

Идя шаг за шагом и делая вычисления в IRB, вы должны быть в состоянии понять это, но дайте мне знать, если у вас есть проблемы. [String # next] (http://ruby-doc.org/core-2.2.0/String.html#method-i-next) возвращает следующий символ умным способом: '' C'.next # = > 'D'; 'Z'.next # =>' AA '; '9'.следующий # =>' 10''. Скажем 'h = {'a' => 1, 'b' => 2}'. [Hash # update] (http://ruby-doc.org/core-2.2.0/Hash.html#method-i-update) (aka 'merge!') Работает следующим образом: 'h.update ({ c '=> 3}) # => {"a" => 1, "b" => 2, "c" => 3} ', [Hash # invert] (http://ruby-doc.org/ core-2.2.0/Hash.html # method-i-update) следующим образом: 'h.invert # => {1 =>" a ", 2 =>" b "}'. –

+0

ahhhh, что новая версия, сверху, по крайней мере немного легче для меня, чтобы сказать, что происходит ... Тем не менее я все равно получаю ошибку // неопределенный метод 'digit_hash 'для main: Object // Я должен include // digit_inv = digit_hash (36) .invert // где-нибудь, чтобы заставить его работать правильно? *** спасибо за разрушение этих методов, что было легко понять = D – HolyMoly

1

Помимо вопроса, вы можете использовать Fixnum # to_s (base) для преобразования базы.

255.to_s(16) # 'ff' 
+0

К сожалению, в указании направления не использовать встроенный метод – HolyMoly

+0

@seinna Вам не нужно изобретать велосипед. Fixnum уже имеет базовые функции преобразования. Вы можете использовать его, если ваша цель не для практики. –

+0

, но я не знал, что .to_s можно использовать в качестве базового конвертера, это интересно! ;) – HolyMoly

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 
+0

Я вижу, где вы собираетесь с этим ... но я еще не совсем рядом с вами ... Я получаю «неопределенный метод' char »для 63933 ': Fixnum на строке // return (num-10 + 65) .char // .... также, я знаю, что это преобразование num в его эквивалент ascii, но какова логика для -10 + 65 бит? – HolyMoly

+0

..также @Mircea, именно так я знаю в будущем и не трачу бесчисленное количество часов, пытаясь использовать миллионы способов его выполнить ... МОЖЕТ хэш использовать для изменения и массива? И может ли условное быть использовано в счетчике, таком как #map или #each? Я искал примеры повсюду, но на обоих фронтах оказался пустым (может быть, это должен быть мой намек? Lol) ....но я не уверен, что это невозможно сделать, или я просто не могу найти пример этого – HolyMoly

+1

huh ... вы положили chr или char? идея довольно проста: 65 - это «А», поэтому все, что есть = = 10, приземлится на A, B, C, D и т. д. Например: 11 будет: 11-10 + 65 => 66. chr для 66 is B. – Mircea

Смежные вопросы