Array to Hash Ruby

后端 未结 9 470
无人及你
无人及你 2021-01-29 17:43

Okay so here\'s the deal, I\'ve been googling for ages to find a solution to this and while there are many out there, they don\'t seem to do the job I\'m looking for.

Ba

相关标签:
9条回答
  • 2021-01-29 18:04
    a = ["item 1", "item 2", "item 3", "item 4"]
    h = Hash[*a] # => { "item 1" => "item 2", "item 3" => "item 4" }
    

    That's it. The * is called the splat operator.

    One caveat per @Mike Lewis (in the comments): "Be very careful with this. Ruby expands splats on the stack. If you do this with a large dataset, expect to blow out your stack."

    So, for most general use cases this method is great, but use a different method if you want to do the conversion on lots of data. For example, @Łukasz Niemier (also in the comments) offers this method for large data sets:

    h = Hash[a.each_slice(2).to_a]
    
    0 讨论(0)
  • 2021-01-29 18:12

    All answers assume the starting array is unique. OP did not specify how to handle arrays with duplicate entries, which result in duplicate keys.

    Let's look at:

    a = ["item 1", "item 2", "item 3", "item 4", "item 1", "item 5"]
    

    You will lose the item 1 => item 2 pair as it is overridden bij item 1 => item 5:

    Hash[*a]
    => {"item 1"=>"item 5", "item 3"=>"item 4"}
    

    All of the methods, including the reduce(&:merge!) result in the same removal.

    It could be that this is exactly what you expect, though. But in other cases, you probably want to get a result with an Array for value instead:

    {"item 1"=>["item 2", "item 5"], "item 3"=>["item 4"]}
    

    The naïve way would be to create a helper variable, a hash that has a default value, and then fill that in a loop:

    result = Hash.new {|hash, k| hash[k] = [] } # Hash.new with block defines unique defaults.
    a.each_slice(2) {|k,v| result[k] << v }
    a
    => {"item 1"=>["item 2", "item 5"], "item 3"=>["item 4"]}
    

    It might be possible to use assoc and reduce to do above in one line, but that becomes much harder to reason about and read.

    0 讨论(0)
  • 2021-01-29 18:14

    This is what I was looking for when googling this:

    [{a: 1}, {b: 2}].reduce({}) { |h, v| h.merge v } => {:a=>1, :b=>2}

    0 讨论(0)
  • 2021-01-29 18:19

    Ruby 2.1.0 introduced a to_h method on Array that does what you require if your original array consists of arrays of key-value pairs: http://www.ruby-doc.org/core-2.1.0/Array.html#method-i-to_h.

    [[:foo, :bar], [1, 2]].to_h
    # => {:foo => :bar, 1 => 2}
    
    0 讨论(0)
  • 2021-01-29 18:22

    Or if you have an array of [key, value] arrays, you can do:

    [[1, 2], [3, 4]].inject({}) do |r, s|
      r.merge!({s[0] => s[1]})
    end # => { 1 => 2, 3 => 4 }
    
    0 讨论(0)
  • 2021-01-29 18:24

    You could try like this, for single array

    irb(main):019:0> a = ["item 1", "item 2", "item 3", "item 4"]
      => ["item 1", "item 2", "item 3", "item 4"]
    irb(main):020:0> Hash[*a]
      => {"item 1"=>"item 2", "item 3"=>"item 4"}
    

    for array of array

    irb(main):022:0> a = [[1, 2], [3, 4]]
      => [[1, 2], [3, 4]]
    irb(main):023:0> Hash[*a.flatten]
      => {1=>2, 3=>4}
    
    0 讨论(0)
提交回复
热议问题