Project

General

Profile

Feature #7241

Enumerable#to_h proposal

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

Status:
Rejected
Priority:
Normal
Assignee:
-
Target version:
-
[ruby-core:48551]

Description

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 http://bugs.ruby-lang.org/issues/666, 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
        Hash.new(&default_or_sym)
      else
        Hash.new(default_or_sym)
      end
      self.each do |el|
        yield hash, el
      end
    elsif !default_or_sym.nil?
      hash = {}
      self.each do |el|
        hash[el] = el.send(default_or_sym)
      end
    else
      return Hash[*self.to_a.flatten(1)]
    end
    hash
  end
end

Examples

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!

Best,
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