простое слияние хешей по массиву ключей и значений в ruby ​​(на примере perl) - PullRequest
7 голосов
/ 17 августа 2011

В Perl, чтобы выполнить обновление хеша на основе массивов ключей и значений, я могу сделать что-то вроде:

@hash{'key1','key2','key3'} = ('val1','val2','val3');

В Ruby я мог бы сделать нечто подобное более сложным способом:

hash.merge!(Hash[ *[['key1','key2','key3'],['val1','val2','val3']].transpose ])

ОК, но я сомневаюсь в эффективности такой процедуры.

Теперь я хотел бы выполнить более сложное назначение в одной строке.

Пример Perl:

(@hash{'key1','key2','key3'}, $key4) = &some_function();

Понятия не имею, возможна ли такая вещь каким-то простым рубиновым способом.Любые подсказки?

Для Perl с ограниченными возможностями, @hash{'key1','key2','key3'} = ('a', 'b', 'c') является срезом хеша и является сокращением для чего-то вроде этого:

$hash{'key1'} = 'a';
$hash{'key2'} = 'b';
$hash{'key3'} = 'c';

Ответы [ 3 ]

4 голосов
/ 17 августа 2011

В Ruby 1.9 Hash.[] может принимать в качестве аргумента массив двузначных массивов (в дополнение к старому поведению простого списка альтернативных аргументов ключ / значение).Так что это относительно просто сделать:

mash.merge!( Hash[ keys.zip(values) ] )

Я не знаю Perl, поэтому я не уверен, что пытается сделать ваше последнее «более сложное задание».Можете ли вы объяснить словами - или с помощью примера ввода и вывода - чего вы пытаетесь достичь?

Редактировать : основываясь на обсуждении в ответе @ fl00r, вы можете сделать это:

def f(n)
  # return n arguments
  (1..n).to_a
end

h = {}
keys = [:a,:b,:c]
*vals, last = f(4)
h.merge!( Hash[ keys.zip(vals) ] )
p vals, last, h
#=> [1, 2, 3]
#=> 4
#=> {:a=>1, :b=>2, :c=>3}

Код *a, b = some_array назначит последний элемент для b и создаст a в виде массива других значений.Этот синтаксис требует Ruby 1.9.Если вам требуется совместимость 1.8, вы можете сделать:

vals = f(4)
last = vals.pop
h.merge!( Hash[ *keys.zip(vals).flatten ] )
3 голосов
/ 17 августа 2011

Вы можете переопределить []= для поддержки этого:

class Hash
  def []=(*args)
    *keys, vals = args # if this doesn't work in your version of ruby, use "keys, vals = args[0...-1], args.last"
    merge! Hash[keys.zip(vals.respond_to?(:each) ? vals : [vals])]
  end
end

Теперь используйте

myhash[:key1, :key2, :key3] = :val1, :val2, :val3
# or
myhash[:key1, :key2, :key3] = some_method_returning_three_values
# or even
*myhash[:key1, :key2, :key3], local_var = some_method_returning_four_values
1 голос
/ 17 августа 2011

вы можете сделать это

def some_method
  # some code that return this:
  [{:key1 => 1, :key2 => 2, :key3 => 3}, 145]
end

hash, key = some_method
puts hash
#=> {:key1 => 1, :key2 => 2, :key3 => 3}
puts key
#=> 145

UPD

В Ruby вы можете выполнять "параллельное назначение", но вы не можете использовать хэши, как вPerl (hash{:a, :b, :c)).Но вы можете попробовать это:

hash[:key1], hash[:key2], hash[:key3], key4 = some_method

, где some_method возвращает массив с 4 элементами.

...