In Perl to perform a hash update based on arrays of keys and values I can do something like:
@hash{'key1','key2','key3'} = ('val1','v开发者_运维技巧al2','val3');
In Ruby I could do something similar in a more complicated way:
hash.merge!(Hash[ *[['key1','key2','key3'],['val1','val2','val3']].transpose ])
OK but I doubt the effectivity of such procedure.
Now I would like to do a more complex assignment in a single line.
Perl example:
(@hash{'key1','key2','key3'}, $key4) = &some_function();
I have no idea if such a thing is possible in some simple Ruby way. Any hints?
For the Perl impaired, @hash{'key1','key2','key3'} = ('a', 'b', 'c')
is a hash slice and is a shorthand for something like this:
$hash{'key1'} = 'a';
$hash{'key2'} = 'b';
$hash{'key3'} = 'c';
In Ruby 1.9 Hash.[]
can take as its argument an array of two-valued arrays (in addition to the old behavior of a flat list of alternative key/value arguments). So it's relatively simple to do:
mash.merge!( Hash[ keys.zip(values) ] )
I do not know perl, so I'm not sure what your final "more complex assignment" is trying to do. Can you explain in words—or with the sample input and output—what you are 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 the other values. This syntax requires Ruby 1.9. If you require 1.8 compatibility, you can do:
vals = f(4)
last = vals.pop
h.merge!( Hash[ *keys.zip(vals).flatten ] )
You could redefine []=
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
you can do this
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 "parallel assignment", but you can't use hashes like you do in Perl (hash{:a, :b, :c)
). But you can try this:
hash[:key1], hash[:key2], hash[:key3], key4 = some_method
where some_method
returns an Array with 4 elements.
精彩评论