2014-09-15 4 views
3

Не удалось найти предыдущее сообщение, которое отвечает на мой вопрос ... Я изучаю использование деструктивных и неразрушающих методов в Ruby. Я нашел ответ на упражнение, над которым я работаю (деструктивное добавление числа в хэш-значения), но я хочу четко сказать, почему некоторые более ранние мои решения не работали. Вот ответ, который работает:Ruby Hash destructive vs. неразрушающий метод

def modify_a_hash(the_hash, number_to_add_to_each_value) 
    the_hash.each { |k, v| the_hash[k] = v + number_to_add_to_each_value} 
    end 

Эти два решения возвращаются в неразрушающий (так как все они используют «каждый» Я не могу понять, почему, чтобы сделать что-то разрушительное является это знак равенства выше, что делает трюк. ?):

def modify_a_hash(the_hash, number_to_add_to_each_value) 
    the_hash.each_value { |v| v + number_to_add_to_each_value} 
    end 

    def modify_a_hash(the_hash, number_to_add_to_each_value) 
    the_hash.each { |k, v| v + number_to_add_to_each_value} 
    end 
+0

В ваших последних двух методов ряд вычисляется, но затем просто отбрасываются, для каждого элемента '' the_hash.values' и the_hash' соответственно. Оба метода возвращают 'the_hash', который не изменяется. Вам нужно записать значения, которые вы вычисляете, в новый хеш. @tadman показывает один путь; другой (для # 2) равен 'h = {}; the_hash.each {| k, v | h [k] = v + num_to_add}; h' или, больше Ruby-like, 'the_hash.each_with_object ({}) {| (k, v), h | h [k] = v + num_to_add} '. –

ответ

2

Термины «разрушительные» и «неразрушающие» здесь немного вводят в заблуждение. Лучше использовать стандартную терминологию «на месте» и «возвращает копию».

Обычно методы, которые изменяют место, имеют ! в конце их имени, чтобы служить предупреждением, например gsub! для строки. Некоторые методы, предшествующие этому соглашению, не имеют их, например push для Array.

= выполняет задание в цикле. Ваши другие примеры на самом деле ничего не полезны, так как each возвращает исходный объект, который повторяется независимо от результатов.

Если вы хотите, чтобы вернуть копию вы бы сделать это:

def modify_a_hash(the_hash, number_to_add) 
    Hash[ 
    the_hash.collect do |k, v| 
     [ k, v + number_to_add ] 
    end 
    ] 
end 

Это будет возвращать копию. Внутренняя операция collect преобразует пары ключ-значение в новые пары ключ-значение с применяемой настройкой. Нет =, так как нет назначения.

Внешний метод Hash[] преобразует эти пары ключ-значение в соответствующий хэш-объект. Затем это возвращается и не зависит от оригинала.

Как правило, метод неразрушающего или возвратного копирования должен создать новую независимую версию того, что она манипулирует с целью хранения результатов. Это относится к String, Array, Hash или к любому другому классу или контейнеру, с которым вы можете работать.

0

Возможно, этот немного другой пример будет полезен.

У нас есть хеш:

2.0.0-p481 :014 > hash 
=> {1=>"ann", 2=>"mary", 3=>"silvia"} 

Тогда мы итерацию над ней и изменить все буквы в верхнем регистре:

2.0.0-p481 :015 > hash.each { |key, value| value.upcase! } 
=> {1=>"ANN", 2=>"MARY", 3=>"SILVIA"} 

оригинальный хэш изменился, потому что мы использовали UPCASE! метод.

Сравните с методом без! знак, который не изменяет значения хэш-функции:

2.0.0-p481 :017 > hash.each { |key, value| value.downcase } 
=> {1=>"ANN", 2=>"MARY", 3=>"SILVIA"}