Feature #5531
closeddeep_value for dealing with nested hashes
Added by weexpectedTHIS (Kyle Peyton) about 14 years ago. Updated about 9 years ago.
Description
This feature request stems from dealing with nested hashes, like the params from a request often dealt with in web frameworks.
Conditional code often needs to be written with multiple logical ANDs in order to achieve what this simple function can:
class Hash
def deep_value(*ks)
if ks.size == 1
return self[ks.shift]
else
val = ks.shift
return (self[val].is_a?(Hash) ? self[val].deep_value(*ks) : nil)
end
end
alias dv deep_value
end
deep_value (dv) will simply recurse over a hash given a set of indexes and return the value at the end.
Example:
foo = {:bar => {:baz => 'blah'}}
foo.dv(:bar, :baz)
-> 'blah'
foo.dv(:cats)
-> nil
        
          
          Updated by ko1 (Koichi Sasada) about 14 years ago
          
          
        
        
          
            Actions
          
          #1
            [ruby-core:40587]
        
      
      (2011/11/01 8:52), Kyle Peyton wrote:
Example:
foo = {:bar => {:baz => 'blah'}}
foo.dv(:bar, :baz)
-> 'blah'
foo.dv(:cats)
-> nil
Just idea.
How about to extend Hash#[] for it?
--
// SASADA Koichi at atdot dot net
        
          
          Updated by rkh (Konstantin Haase) about 14 years ago
          
          
        
        
          
            Actions
          
          #2
            [ruby-core:40589]
        
      
      What's the difference (usability wise) between
hash[:foo][:bar]
and
hash.dv(:foo, :bar)
Konstantin
On Oct 31, 2011, at 16:52 , Kyle Peyton wrote:
Issue #5531 has been reported by Kyle Peyton.
Feature #5531: deep_value for dealing with nested hashes
http://redmine.ruby-lang.org/issues/5531Author: Kyle Peyton
Status: Open
Priority: Normal
Assignee:
Category:
Target version:This feature request stems from dealing with nested hashes, like the params from a request often dealt with in web frameworks.
Conditional code often needs to be written with multiple logical ANDs in order to achieve what this simple function can:
class Hash
def deep_value(*ks)
if ks.size
        
          
          Updated by rkh (Konstantin Haase) about 14 years ago
          
          
        
        
          
            Actions
          
          #3
            [ruby-core:40590]
        
      
      What's the difference (usability wise) between
hash[:foo][:bar]
and
hash.dv(:foo, :bar)
Konstantin
On Oct 31, 2011, at 16:52 , Kyle Peyton wrote:
Issue #5531 has been reported by Kyle Peyton.
Feature #5531: deep_value for dealing with nested hashes
http://redmine.ruby-lang.org/issues/5531Author: Kyle Peyton
Status: Open
Priority: Normal
Assignee:
Category:
Target version:This feature request stems from dealing with nested hashes, like the params from a request often dealt with in web frameworks.
Conditional code often needs to be written with multiple logical ANDs in order to achieve what this simple function can:
class Hash
def deep_value(*ks)
if ks.size
        
          
          Updated by rkh (Konstantin Haase) about 14 years ago
          
          
        
        
          
            Actions
          
          #4
            [ruby-core:40591]
        
      
      Never mind, got it.
On Oct 31, 2011, at 17:32 , Haase, Konstantin wrote:
What's the difference (usability wise) between
hash[:foo][:bar]
and
hash.dv(:foo, :bar)
Konstantin
On Oct 31, 2011, at 16:52 , Kyle Peyton wrote:
Issue #5531 has been reported by Kyle Peyton.
Feature #5531: deep_value for dealing with nested hashes
http://redmine.ruby-lang.org/issues/5531Author: Kyle Peyton
Status: Open
Priority: Normal
Assignee:
Category:
Target version:This feature request stems from dealing with nested hashes, like the params from a request often dealt with in web frameworks.
Conditional code often needs to be written with multiple logical ANDs in order to achieve what this simple function can:
class Hash
def deep_value(*ks)
if ks.size
        
          
          Updated by Eregon (Benoit Daloze) about 14 years ago
          
          
        
        
          
            Actions
          
          #5
            [ruby-core:40618]
        
      
      On 1 November 2011 01:26, SASADA Koichi ko1@atdot.net wrote:
(2011/11/01 8:52), Kyle Peyton wrote:
Example:
foo = {:bar => {:baz => 'blah'}}
foo.dv(:bar, :baz)
-> 'blah'
foo.dv(:cats)
-> nilJust idea.
How about to extend Hash#[] for it?--
// SASADA Koichi at atdot dot net
That would be nice.
        
          
          Updated by alexeymuranov (Alexey Muranov) about 14 years ago
          
          
        
        
          
            Actions
          
          #6
            [ruby-core:40619]
        
      
      Konstantin Haase wrote:
Never mind, got it.
On Oct 31, 2011, at 17:32 , Haase, Konstantin wrote:
What's the difference (usability wise) between
hash[:foo][:bar]
and
hash.dv(:foo, :bar)
Konstantin
I'll answer anyway if someone else didn't get it :).
{ :foo => 1 }[2][3] raises NoMethodError, and { :foo => 1 }.dv(2,3) or { :foo => 1 }[2,3] should return nil.
Update: also it is possible to keep the list of all arguments in a single variable and call { :foo => 1 }.dv(*args)
        
          
          Updated by alexeymuranov (Alexey Muranov) about 14 years ago
          
          
        
        
          
            Actions
          
          #7
            [ruby-core:40624]
        
      
      I can think of the following questions/objections to the suggested method definition:
- is 
{ 1 => 2}.dv(1,1) # => nilthe desired result? - this method examines the (super)class name of an object, rather than the behavior of an object, so does not allow to mix nested hashes and arrays,
 - this method calls itself recursively, while a loop would suffice.
 
The following is not a serious suggestion, but seriously, how about:
class Object
def deep_value(*keys)
obj = self
obj = obj[keys.shift] while !keys.empty? && obj.respond_to?(:[])
return obj
end
end
(For this to work well it will be important to call it #deep_value and not to redefine #[].)
Update. Another suggestion, probably a better one (at least simpler):
class Object
def deep_value(*keys)
obj = self
obj = obj[keys.shift] until keys.empty? || obj.nil?
return obj
end
end
        
          
          Updated by nobu (Nobuyoshi Nakada) about 14 years ago
          
          
        
        
          
            Actions
          
          #8
            [ruby-core:40627]
        
      
      
    
        
          
          Updated by alexeymuranov (Alexey Muranov) about 14 years ago
          
          
        
        
          
            Actions
          
          #9
            [ruby-core:40628]
        
      
      Nobuyoshi Nakada wrote:
=begin
What about:class Hash
def
keys.inject(self) {|container, key| container.fetch(key) {return}}
end
end
=end
Just a small remark about defining this exclusively for Hash: what if some of the values is not a Hash but responds to #fetch? (will not look consistent enough to me).
        
          
          Updated by trans (Thomas Sawyer) almost 14 years ago
          
          
        
        
          
            Actions
          
          #10
            [ruby-core:40772]
        
      
      Probably best to use #[] internally too.
class Hash
  def [](*keys)
    keys.inject(self) {|container, key| value = container[key]; value ? value : return value}
  end
end
@Alexey you may have a point. But I suspect it would need to be conditioned off of responding to #to_h or #to_hash instead of using is_a?(Hash).
        
          
          Updated by neleai (Ondrej Bilka) almost 14 years ago
          
          
        
        
          
            Actions
          
          #11
            [ruby-core:40784]
        
      
      Do you need hash or something like multidimensional hash class that uses [], each iterates on nested...
On Sun, Nov 06, 2011 at 05:48:52PM +0900, Thomas Sawyer wrote:
Issue #5531 has been updated by Thomas Sawyer.
Probably best to use #[] internally too.
class Hash def [](*keys) keys.inject(self) {|container, key| value = container[key]; value ? value : return value} end end@Alexey you may have a point. But I suspect it would need to be conditioned off of responding to #to_h or #to_hash instead of using
is_a?(Hash).
Feature #5531: deep_value for dealing with nested hashes
http://redmine.ruby-lang.org/issues/5531Author: Kyle Peyton
Status: Open
Priority: Normal
Assignee:
Category:
Target version:This feature request stems from dealing with nested hashes, like the params from a request often dealt with in web frameworks.
Conditional code often needs to be written with multiple logical ANDs in order to achieve what this simple function can:
class Hash
def deep_value(*ks)
if ks.size == 1
return self[ks.shift]
else
val = ks.shift
return (self[val].is_a?(Hash) ? self[val].deep_value(*ks) : nil)
end
endalias dv deep_value
enddeep_value (dv) will simply recurse over a hash given a set of indexes and return the value at the end.
Example:
foo = {:bar => {:baz => 'blah'}}
foo.dv(:bar, :baz)
-> 'blah'
foo.dv(:cats)
-> nil
--
network packets travelling uphill (use a carrier pigeon)
        
          
          Updated by mame (Yusuke Endoh) over 13 years ago
          
          
        
        
          
            Actions
          
          #12
        
      
      - Status changed from Open to Assigned
 - Assignee set to matz (Yukihiro Matsumoto)
 
        
          
          Updated by weexpectedTHIS (Kyle Peyton) over 13 years ago
          
          
        
        
          
            Actions
          
          #13
            [ruby-core:43882]
        
      
      What's the status of this issue? Good idea? Bad idea?
        
          
          Updated by weexpectedTHIS (Kyle Peyton) over 13 years ago
          
          
        
        
          
            Actions
          
          #14
            [ruby-core:45893]
        
      
      I'd really like to see this in the next version of Ruby, it's a really common pattern.
        
          
          Updated by weexpectedTHIS (Kyle Peyton) about 13 years ago
          
          
        
        
          
            Actions
          
          #15
            [ruby-core:47796]
        
      
      I think there is a strong case for this logic built in to ruby.
        
          
          Updated by mame (Yusuke Endoh) almost 13 years ago
          
          
        
        
          
            Actions
          
          #16
            [ruby-core:49914]
        
      
      - Priority changed from Normal to 3
 - Target version set to 2.6
 
matz expressed a negative opinion for similar proposal (in Japanese, #5550)
The original in Japanese:
Hashの本質はkey-valueのマッピングなので、valueが再帰的にHashであることを想定した(再帰的なHashでなければ役に立たない)メソッドを追加することには抵抗があります。
English translation:
The essence of Hash is a key-value mapping. I'm negative for adding a method that assumes that the value is a recursive hash, or a method that is useful only for a recursive hash.
--
Yusuke Endoh mame@tsg.ne.jp
        
          
          Updated by dan.erikson (Dan Erikson) about 9 years ago
          
          
        
        
          
            Actions
          
          #17
            [ruby-core:77528]
        
      
      I believe this has recently been implemented as Hash#dig.
        
          
          Updated by shyouhei (Shyouhei Urabe) about 9 years ago
          
          
        
        
          
            Actions
          
          #18
            [ruby-core:77827]
        
      
      - Status changed from Assigned to Closed
 
Dan Erikson wrote:
I believe this has recently been implemented as
Hash#dig.
Indeed. Closing peacefully.