Hash :: Recursive traversing and stripping the values

Discussion in 'Ruby' started by vimal, Feb 16, 2009.

  1. vimal

    vimal Guest

    Hi,
    I am a Ruby Newbie.

    I wrote a function for stripping all the values(a recursive one if
    it is a nested hash) but i almost end up in an
    error suggesting "Error => in `strip_hash_values': stack level too
    deep (SystemStackError)".
    Can someone help me with this.

    -------------------------------------------
    Here's the code:
    -------------------------------------------

    def strip_hash_values(hash)

    hash.each do |k, v|

    if v.class == String
    hash[k] == v.strip!

    elsif v.class == Array
    v.each do |vv|
    vv.strip!
    end

    elsif v.class == Hash
    strip_hash_values(hash)
    end

    end

    end

    Thanx,
    Vimal Das
    vimal, Feb 16, 2009
    #1
    1. Advertising

  2. vimal <> writes:

    > Hi,
    > I am a Ruby Newbie.
    >
    > I wrote a function for stripping all the values(a recursive one if
    > it is a nested hash) but i almost end up in an
    > error suggesting "Error => in `strip_hash_values': stack level too
    > deep (SystemStackError)".
    > Can someone help me with this.


    Perhaps a circular data structure is the problem:

    irb(main):001:0> h = Hash.new
    {}
    irb(main):002:0> h[:ha]=Hash.new
    {}
    irb(main):003:0> h[:ha][:ho]=h
    {:ha=>{:ho=>{...}}}
    irb(main):004:0> h
    {:ha=>{:ho=>{...}}}
    irb(main):005:0> h[:ha][:ho][:ha]
    {:ho=>{:ha=>{...}}}
    irb(main):006:0> h[:ha][:ho][:ha][:ho]
    {:ha=>{:ho=>{...}}}
    irb(main):007:0>


    --
    __Pascal Bourguignon__
    Pascal J. Bourguignon, Feb 16, 2009
    #2
    1. Advertising

  3. vimal

    vimal Guest

    So is there any other way to carry out this stripping
    functionality thoughout the hash(if nested too)!!!
    vimal, Feb 16, 2009
    #3
  4. vimal

    lasitha Guest

    On Mon, Feb 16, 2009 at 5:50 PM, vimal <> wrote:
    > error suggesting "Error => in `strip_hash_values': stack level too
    > deep (SystemStackError)".



    Vimal, take a very close look at the recursive call:

    > ...
    > elsif v.class == Hash
    > strip_hash_values(hash)
    > end
    > ...


    You have a simple typo/bug there.

    When i free up a couple of minutes i'll follow up with some additional
    observations.

    HTH for now,
    lasitha
    lasitha, Feb 16, 2009
    #4
  5. vimal

    lasitha Guest

    On Mon, Feb 16, 2009 at 6:20 PM, lasitha <> wrote:
    > On Mon, Feb 16, 2009 at 5:50 PM, vimal <> wrote:
    >> error suggesting "Error => in `strip_hash_values': stack level too
    >> deep (SystemStackError)".

    >
    >
    > Vimal, take a very close look at the recursive call:
    >
    >> ...
    >> elsif v.class == Hash
    >> strip_hash_values(hash)
    >> end
    >> ...

    >
    > You have a simple typo/bug there.
    >


    Some further observations:

    1. This line uses a comparison operator, not the assignment operator:
    hash[k] == v.strip!

    2. We're getting away with the above typo because we're using #strip!
    (the version with side-effect). So the string v is being modified in
    place and therefore doesn't need to be assigned back to hash[k].
    Needless to say this is redundant - we should either use #strip or get
    rid of the assignment.

    3. A case statement may be a better choice than if/else. I tend to
    consider a case statement as soon as i have more than two branches -
    it reads slightly cleaner and is easier to add new cases to. See the
    example below.

    4. I would consider adding a catch-all clause and failing fast with
    an exception if the hash contains an unhandled type. Even if you
    later choose to silently ignore unhandled types, keeping the else
    clause in the code usefully documents your intent. Again, see the
    example below.

    The code below includes rspec (test) code in case that's of use/inspiration.

    Cheers,
    lasitha.


    The following code can be also be seen at:
    http://pastie.org/390656

    def strip_hash_values(hash)

    hash.each_value do |v|
    case v
    when String then v.strip!
    when Array then v.each {|i| i.strip! }
    when Hash then strip_hash_values(v)
    else raise ArgumentError, "Unhandled type #{v.class}"
    end
    end

    end


    describe 'strip_hash_values' do

    it 'should recurse and strip hash values' do
    hash = { c: ' s ', a: [' an ', ' array '], h: { nested: ' hash ' } }
    stripped = { c: 's', a: [ 'an', 'array' ], h: { nested: 'hash' } }
    strip_hash_values(hash).should eql(stripped)
    end

    it 'should raise an exception if the hash contains an unhandled type' do
    lambda { strip_hash_values( { e: 1 } ) }.should raise_error(ArgumentError)
    end

    end
    lasitha, Feb 16, 2009
    #5
  6. >>> sender: "vimal" date: "Mon, Feb 16, 2009 at 09:40:02PM +0900" <<<EOQ
    > So is there any other way to carry out this stripping
    > functionality thoughout the hash(if nested too)!!!
    >>>EOQ

    Of course there is:

    elsif v.class == Hash
    strip_hash_values(hash)
    end

    should actually be:

    elsif v.class == Hash
    strip_hash_values(v)
    end

    Additionally, you could 'cheat' and use "case" (no more need to check
    the type/class manually):

    def strip_hash_values(hash)
    hash.each do |k, v|
    case v
    when String
    v.strip!
    when Array
    v.each {|vv| vv.strip!}
    when Hash
    strip_hash_values(v)
    end
    end
    end


    Cheers,
    Alex
    Alexandru E. Ungur, Feb 16, 2009
    #6
  7. vimal

    vimal Guest

    On Feb 16, 7:03 pm, "Alexandru E. Ungur"
    <> wrote:
    > >>> sender: "vimal" date: "Mon, Feb 16, 2009 at 09:40:02PM +0900" <<<EOQ

    > > So is there any other way to carry out thisstripping
    > > functionality thoughout thehash(if nested too)!!!
    > >>>EOQ

    >
    > Of course there is:
    >
    >         elsif v.class ==Hash
    >           strip_hash_values(hash)
    >         end
    >
    > should actually be:
    >
    >         elsif v.class ==Hash
    >           strip_hash_values(v)
    >         end
    >
    > Additionally, you could 'cheat' and use "case" (no more need to check
    > the type/class manually):


    This is what an user expects to learn(some additional tips) and
    master a scripting lang

    >
    > def strip_hash_values(hash)
    >  hash.each do |k, v|      
    >         case v
    >     when String
    >       v.strip!
    >     when Array
    >       v.each {|vv| vv.strip!}
    >     whenHash
    >       strip_hash_values(v)
    >         end
    >   end
    > end
    >
    > Cheers,
    > Alex


    Thanks for all your suggestions
    I now figure it how.
    vimal, Feb 17, 2009
    #7
  8. vimal

    vimal Guest

    Hi Guys,

    I found out another way to do this using a 'lambda' function
    I am just curious to know, how effective is this compared to the
    above mentioned suggestions


    -----------------------------------------------------------------------------------
    Code modified from source http://blog.hasmanythrough.com/2008/6/20/recursive-lambda

    -----------------------------------------------------------------------------------

    thunk = lambda do |key,value|
    case value
    when String then value.strip!
    when Hash then value.each(&thunk)
    when Array then value.each {|vv| vv.strip!}
    end
    end

    --------------------------------
    Call
    --------------------------------

    <Hash>.each(&thunk)

    Thanks,
    Vimal Das
    Waiting with curiosity :-|
    vimal, Feb 17, 2009
    #8
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. thomson
    Replies:
    0
    Views:
    317
    thomson
    Dec 27, 2005
  2. rp
    Replies:
    1
    Views:
    499
    red floyd
    Nov 10, 2011
  3. Trans
    Replies:
    8
    Views:
    147
    Trans
    Apr 13, 2005
  4. Me
    Replies:
    3
    Views:
    93
    Anno Siegel
    Jan 20, 2006
  5. Bryan
    Replies:
    6
    Views:
    200
    -berlin.de
    Apr 11, 2007
Loading...

Share This Page