Simple hash merge over an array of keys and values ​​in ruby ​​(with perl example)

In Perl, to do a hash update based on arrays of keys and values, I can do something like:

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

In Ruby, I could do something like this in a more complex way:

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

OK, but I doubt the effectiveness of such a procedure.

Now I would like to make a more complex assignment in one line.

Perl example:

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

I have no idea if this is possible in some simple Ruby way. Any clues?

For the vulnerable Perl, @hash{'key1','key2','key3'} = ('a', 'b', 'c') is a hash fragment and is a shorthand for something like this:

 $hash{'key1'} = 'a'; $hash{'key2'} = 'b'; $hash{'key3'} = 'c'; 
+7
source share
3 answers

You can override []= to support this:

 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 

Now use

 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 
+3
source

In Ruby 1.9 Hash.[] Can take an array of two-digit arrays as an argument (in addition to the old behavior of a flat list of alternative key / value arguments). So this is relatively simple:

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

I don't know perl, so I'm not sure I'm trying to do your final β€œmore difficult job". Can you explain with the words / mdash or with the sample input and output & mdash, what are you trying to achieve?

Edit : based on the discussion in @ fl00r's answer you can do this:

 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} 

The code *a, b = some_array will assign the last element to b and create a as an array of other values. This syntax requires Ruby 1.9. If you require compatibility with 1.8, you can do:

 vals = f(4) last = vals.pop h.merge!( Hash[ *keys.zip(vals).flatten ] ) 
+4
source

You can do it

 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

In Ruby, you can do a β€œparallel assignment,” but you cannot use hashes like in Perl ( hash{:a, :b, :c) ). But you can try the following:

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

where some_method returns an array with 4 elements.

+1
source

All Articles