Как обновить хэш-элемент Ruby внутри цикла поверх этого хеша? - PullRequest
2 голосов
/ 30 июня 2010

Я переношу свой PHP-код на Ruby, и в какой-то момент мне нужно обновить хеш-элементы внутри цикла. Например:

compositions.each_pair do |element,params|
  params['composition'].each_pair do |item,data| 
    data['af'] /= params['af sum']
    data['mf'] /= params['mass']
  end
end

Я мог бы сделать это, используя индексы предметов, но это будет ужасно. Есть ли хороший способ связать переменные цикла с соответствующими элементами хеша? В PHP я бы написал &$params и &$data в соответствующих циклах. Или может быть лучшее предложение?


Обновление

Два теста, чтобы продемонстрировать проблему. Первый:

a={'a'=>1, 'b'=>2, 'c'=>3}

a.each_pair do |k,v|
  v += 1
end
p a # =>  {"a"=>1, "b"=>2, "c"=>3}

и второй

a.each_pair do |k,v|
  a[k] += 1
end
p a # =>  {"a"=>2, "b"=>3, "c"=>4}

Update2

Благодаря Младену (см. Ниже) я понял разницу между этими двумя случаями. Однако у меня все еще остается вопрос: как обновить элемент data (а не только его собственные элементы)? Допустим, мы добавляем

data = data['af'] + data['mf']

к внутренней петле.

1 Ответ

2 голосов
/ 30 июня 2010

Кажется, что код из вопроса работает нормально:

compositions = {1 => {'af sum' => 100.0, 'mass' => 200.0, 'composition' => {1 => {'af' => 5.0, 'mf' => 6.0}, 2  => {'af' => 7.0, 'mf' => 8.0}, 3  => {'af' => 9.0, 'mf' => 16.0}}}}
#=> {1=>{"af sum"=>100.0, "mass"=>200.0, "composition"=>{1=>{"af"=>5.0, "mf"=>6.0}, 2=>{"af"=>7.0, "mf"=>8.0}, 3=>{"af"=>9.0, "mf"=>16.0}}}}
compositions.each_pair do |element,params|
  params['composition'].each_pair do |item,data| 
    data['af'] /= params['af sum']
    data['mf'] /= params['mass']
  end
end
#=> {1=>{"af sum"=>100.0, "mass"=>200.0, "composition"=>{1=>{"af"=>0.05, "mf"=>0.03}, 2=>{"af"=>0.07, "mf"=>0.04}, 3=>{"af"=>0.09, "mf"=>0.08}}}}

Но пример структуры в значительной степени угадывается из кода, OP должен опубликовать пример, с которым он работает, чтобы мы могли добиться некоторого прогресса.

Edit:

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

Однако, если вы работаете с методами мутации, вы изменяете сами объекты на месте, поэтому вам не нужно переназначать их хешу. Например:

{1 => 'foo', 2 => 'bar'}.each{|k,v| v.swapcase!}
#=> {1=>"FOO", 2=>"BAR"}

но

{1 => 'foo', 2 => 'bar'}.each{|k,v| v = 'baz'}
#=> {1=>"foo", 2=>"bar"}

Редактировать 2:

Я думаю, у вас есть проблемы с пониманием, что такое k и v в примерах. Они являются просто локальными переменными в блоке, они начинают с ссылки на то, что находится в хэше, но то, на что они ссылаются, может быть изменено в ходе блока, как и любая другая переменная. Это изменение не отразится на хэше. Вам нужно изменить сам объект , а не ссылку на него, чтобы фактически изменить его.

Посмотрите на этот, еще более простой пример, без хэшей, блоки mumbo-jumbo:

a = 5
b = a
b += 1
a # => 5
b # => 6

Это так просто.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...