开发者

simple hash merge by array of keys and values in ruby (with perl example)

开发者 https://www.devze.com 2023-03-29 01:32 出处:网络
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 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.

0

精彩评论

暂无评论...
验证码 换一张
取 消