Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Ruby > Hash :: Recursive traversing and stripping the values

Reply
Thread Tools

Hash :: Recursive traversing and stripping the values

 
 
vimal
Guest
Posts: n/a
 
      02-16-2009
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
 
Reply With Quote
 
 
 
 
Pascal J. Bourguignon
Guest
Posts: n/a
 
      02-16-2009
vimal <(E-Mail Removed)> 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__
 
Reply With Quote
 
 
 
 
vimal
Guest
Posts: n/a
 
      02-16-2009
So is there any other way to carry out this stripping
functionality thoughout the hash(if nested too)!!!
 
Reply With Quote
 
lasitha
Guest
Posts: n/a
 
      02-16-2009
On Mon, Feb 16, 2009 at 5:50 PM, vimal <(E-Mail Removed)> 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

 
Reply With Quote
 
lasitha
Guest
Posts: n/a
 
      02-16-2009
On Mon, Feb 16, 2009 at 6:20 PM, lasitha <(E-Mail Removed)> wrote:
> On Mon, Feb 16, 2009 at 5:50 PM, vimal <(E-Mail Removed)> 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

 
Reply With Quote
 
Alexandru E. Ungur
Guest
Posts: n/a
 
      02-16-2009
>>> 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

 
Reply With Quote
 
vimal
Guest
Posts: n/a
 
      02-17-2009
On Feb 16, 7:03*pm, "Alexandru E. Ungur"
<(E-Mail Removed)> 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.


 
Reply With Quote
 
vimal
Guest
Posts: n/a
 
      02-17-2009
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/...cursive-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



 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
hash of hash of hash of hash in c++ rp C++ 1 11-10-2011 04:45 PM
Traversing a hash with array refs as keys? Bryan Perl Misc 6 04-11-2007 11:55 AM
traversing a hash two using serveral conditions Me Perl Misc 3 01-20-2006 12:37 PM
Traversing Hash or XML? Which is Fast thomson ASP .Net 0 12-27-2005 05:57 AM
help traversing and modifying hash key and value inplace Trans Ruby 8 04-13-2005 02:52 PM



Advertisments