Feature #7241

Enumerable#to_h proposal

Added by nathan.f77 (Nathan Broadbent) almost 8 years ago. Updated over 7 years ago.

Target version:


I often use the inject method to build a hash, but I always find it annoying when I need to return the hash at the end of the block.
This means that I often write code like:

[1,2,3,4,5].inject({}) {|hash, el| hash[el] = el * 2; hash }

I'm proposing an Enumerable#to_h method that would let me write:

[1,2,3,4,5].to_h {|h, el| h[el] = el * 2 }

I saw the proposal at, but I would not be in favor of his implementation.
I believe the implementation should be similar to inject, so that the hash object and next element are passed to the block. The main difference to the inject method is that we would be modifying the hash in place, instead of relying on the block's return value.

As well as providing support for the case above, I have also considered other cases where the to_h method would be useful.
I thought it would be useful if symmetry were provided for the Hash#to_a method, such that:

hash.to_a.to_h == hash  # => true

(See example 2)

I've allowed developers to provide a symbol instead of a block, so that each element in the collection will be passed to that named method. (See example 3)

Finally, hashes can be given a default value, or a Proc that returns the default value. (See examples 4 & 5)

Heres an example implementation that I would be happy to rewrite in C if necessary:

module Enumerable
  def to_h(default_or_sym = nil)
    if block_given?
      hash = if Proc === default_or_sym
      self.each do |el|
        yield hash, el
    elsif !default_or_sym.nil?
      hash = {}
      self.each do |el|
        hash[el] = el.send(default_or_sym)
      return Hash[*self.to_a.flatten(1)]


1) Build a hash from array elements

[1,2,3,4,5].to_h {|h, el| h[el] = el * 2 }

=> {1=>2, 2=>4, 3=>6, 4=>8, 5=>10}

2) Provides symmetry for Hash.to_a (i.e. you can call hash.to_a.to_h)

[[1, 2], [3, 4], [5, 6]].to_h

=> {1=>2, 3=>4, 5=>6}

3) Build a hash by calling a method on each array element

["String", "Another String"].to_h(:size)

=> {"String"=>6, "Another String"=>14}

4) Hash with default value

[4,5,6,5].to_h(0) {|h, el| h[el] += el }

=> {4=>4, 5=>10, 6=>6}

5) Hash with default value returned from Proc

default_proc = -> hash, key { hash[key] = "go fish: #{key}" }
[4,5,6].to_h(default_proc) {|h, el| h[el].upcase! }

=> {4=>"GO FISH: 4", 5=>"GO FISH: 5", 6=>"GO FISH: 6"}

Thanks for your time, and please let me know your thoughts!

Nathan Broadbent

Related issues

Related to Ruby master - Feature #5008: Equal rights for Hash (like Array, String, Integer, Float)Rejectedmatz (Yukihiro Matsumoto)07/10/2011Actions
Related to Ruby master - Feature #4151: Enumerable#categorizeRejectedakr (Akira Tanaka)Actions
Is duplicate of Ruby master - Feature #666: Enumerable::to_hashRejectedmatz (Yukihiro Matsumoto)10/20/2008Actions
Has duplicate Ruby master - Feature #7292: Enumerable#to_hClosedmarcandre (Marc-Andre Lafortune)11/07/2012Actions

Also available in: Atom PDF