What is the best way to convert an array to a hash in Ruby

后端 未结 11 1969
佛祖请我去吃肉
佛祖请我去吃肉 2020-11-28 18:18

In Ruby, given an array in one of the following forms...

[apple, 1, banana, 2]
[[apple, 1], [banana, 2]]

...what is the best way to convert

相关标签:
11条回答
  • 2020-11-28 18:52

    NOTE: For a concise and efficient solution, please see Marc-André Lafortune's answer below.

    This answer was originally offered as an alternative to approaches using flatten, which were the most highly upvoted at the time of writing. I should have clarified that I didn't intend to present this example as a best practice or an efficient approach. Original answer follows.


    Warning! Solutions using flatten will not preserve Array keys or values!

    Building on @John Topley's popular answer, let's try:

    a3 = [ ['apple', 1], ['banana', 2], [['orange','seedless'], 3] ]
    h3 = Hash[*a3.flatten]
    

    This throws an error:

    ArgumentError: odd number of arguments for Hash
            from (irb):10:in `[]'
            from (irb):10
    

    The constructor was expecting an Array of even length (e.g. ['k1','v1,'k2','v2']). What's worse is that a different Array which flattened to an even length would just silently give us a Hash with incorrect values.

    If you want to use Array keys or values, you can use map:

    h3 = Hash[a3.map {|key, value| [key, value]}]
    puts "h3: #{h3.inspect}"
    

    This preserves the Array key:

    h3: {["orange", "seedless"]=>3, "apple"=>1, "banana"=>2}
    
    0 讨论(0)
  • 2020-11-28 18:53

    Update

    Ruby 2.1.0 is released today. And I comes with Array#to_h (release notes and ruby-doc), which solves the issue of converting an Array to a Hash.

    Ruby docs example:

    [[:foo, :bar], [1, 2]].to_h    # => {:foo => :bar, 1 => 2}
    
    0 讨论(0)
  • 2020-11-28 18:53

    You can also simply convert a 2D array into hash using:

    1.9.3p362 :005 > a= [[1,2],[3,4]]
    
     => [[1, 2], [3, 4]]
    
    1.9.3p362 :006 > h = Hash[a]
    
     => {1=>2, 3=>4} 
    
    0 讨论(0)
  • 2020-11-28 19:00

    Appending to the answer but using anonymous arrays and annotating:

    Hash[*("a,b,c,d".split(',').zip([1,2,3,4]).flatten)]
    

    Taking that answer apart, starting from the inside:

    • "a,b,c,d" is actually a string.
    • split on commas into an array.
    • zip that together with the following array.
    • [1,2,3,4] is an actual array.

    The intermediate result is:

    [[a,1],[b,2],[c,3],[d,4]]
    

    flatten then transforms that to:

    ["a",1,"b",2,"c",3,"d",4]
    

    and then:

    *["a",1,"b",2,"c",3,"d",4] unrolls that into "a",1,"b",2,"c",3,"d",4

    which we can use as the arguments to the Hash[] method:

    Hash[*("a,b,c,d".split(',').zip([1,2,3,4]).flatten)]
    

    which yields:

    {"a"=>1, "b"=>2, "c"=>3, "d"=>4}
    
    0 讨论(0)
  • 2020-11-28 19:04

    Simply use Hash[*array_variable.flatten]

    For example:

    a1 = ['apple', 1, 'banana', 2]
    h1 = Hash[*a1.flatten(1)]
    puts "h1: #{h1.inspect}"
    
    a2 = [['apple', 1], ['banana', 2]]
    h2 = Hash[*a2.flatten(1)]
    puts "h2: #{h2.inspect}"
    

    Using Array#flatten(1) limits the recursion so Array keys and values work as expected.

    0 讨论(0)
提交回复
热议问题