Feature #5531

deep_value for dealing with nested hashes

Added by weexpectedTHIS (Kyle Peyton) 7 months ago. Updated about 1 month ago.

[ruby-core:40586]
Status:Assigned Start date:11/01/2011
Priority:Normal Due date:
Assignee:matz (Yukihiro Matsumoto) % Done:

0%

Category:-
Target version:-

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

History

Updated by ko1 (Koichi Sasada) 7 months ago

(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) 7 months ago

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/5531 > > Author: 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) 7 months ago

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/5531 > > Author: 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) 7 months ago

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/5531 >> >> Author: 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) 7 months ago

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) >> -> nil > > Just idea. > How about to extend Hash#[] for it? > > -- > // SASADA Koichi at atdot dot net That would be nice.

Updated by alexeymuranov (Alexey Muranov) 7 months ago

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) 7 months ago

I can think of the following questions/objections to the suggested method definition: 1. is `{ 1 => 2}.dv(1,1) # => nil` the desired result? 2. 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, 3. 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) 7 months ago

What about:

class Hash
  def [](*keys)
    keys.inject(self) {|container, key| container.fetch(key) {return}}
  end
end

Updated by alexeymuranov (Alexey Muranov) 7 months ago

Nobuyoshi Nakada wrote: > =begin > What about: > > class Hash > def [](*keys) > 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) 7 months ago

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) 7 months ago

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/5531 > > Author: 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 > 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 > > > > -- > http://redmine.ruby-lang.org -- network packets travelling uphill (use a carrier pigeon)

Updated by mame (Yusuke Endoh) about 1 month ago

  • Status changed from Open to Assigned
  • Assignee set to matz (Yukihiro Matsumoto)

Updated by weexpectedTHIS (Kyle Peyton) about 1 month ago

What's the status of this issue? Good idea? Bad idea?

Also available in: Atom PDF