Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Ruby > No Keys, nor other hash methods on multidimensional hash

Reply
Thread Tools

No Keys, nor other hash methods on multidimensional hash

 
 
Xeno Campanoli
Guest
Posts: n/a
 
      08-22-2005
Okay, I'm taking the example I got last week for multi-dimensional hashes, and
I don't have access to any Hash methods:

pHash = lambda { Hash.new {|h,k| h[k] = pHash.call }
pHash['1']['a'] = "one"
p pHash.keys

I run this and get the result:

...undefined method `keys' for ... (NoMethodError)

Do I need to dereference or something, or is this just something that doesn't
work after all?

Sincerely, Xeno Campanoli, Ruby neophyte and general paraphernalian.


 
Reply With Quote
 
 
 
 
David A. Black
Guest
Posts: n/a
 
      08-22-2005
Hi --

On Tue, 23 Aug 2005, Xeno Campanoli wrote:

> Okay, I'm taking the example I got last week for multi-dimensional hashes, and
> I don't have access to any Hash methods:
>
> pHash = lambda { Hash.new {|h,k| h[k] = pHash.call }
> pHash['1']['a'] = "one"
> p pHash.keys
>
> I run this and get the result:
>
> ...undefined method `keys' for ... (NoMethodError)
>
> Do I need to dereference or something, or is this just something that doesn't
> work after all?


Try this:

hash_lambda = lambda { Hash.new {|h,k| h[k] = hash_lambda.call } }
hash = hash_lambda[]
hash['1']['a'] = "one"
p hash.keys


David

--
David A. Black



 
Reply With Quote
 
 
 
 
Martin DeMello
Guest
Posts: n/a
 
      08-22-2005
Xeno Campanoli <> wrote:
> Okay, I'm taking the example I got last week for multi-dimensional hashes, and
> I don't have access to any Hash methods:
>
> pHash = lambda { Hash.new {|h,k| h[k] = pHash.call }


lambda creates an anonymous function, which in this case returns a hash.
hash_factory might have been a better variable name:

hash_factory = lambda { Hash.new {|h,k| h[k] = hash_factory.call }}

How it works: Hash.new {|h,k| block} creates a new hash, and calls the
block whenever the hash is called with a nonexistent key. h and k, the
two parameters passed to the block, are the hash itself and the key you
tried to look up.

lambda {Hash.new} creates an anonymous function that returns a hash. The
clever part here is that we capture a reference to the function we're
defining, and pass that reference into the block we pass to the hash
(this all works because lambdas are lazily evaluated). So now every time
we call the hash with a missing key, the hash_factory is called again
and generates a new autovivifying hash to store as the value.

Here's how you use it:

hash = hash_factory.call
hash[1][2][3] #=> nil, but the hash will now have the keys

martin




 
Reply With Quote
 
Bill Kelly
Guest
Posts: n/a
 
      08-22-2005
Hi,

From: "Xeno Campanoli" <>
>
> Okay, I'm taking the example I got last week for multi-dimensional hashes, and
> I don't have access to any Hash methods:
>
> pHash = lambda { Hash.new {|h,k| h[k] = pHash.call }
> pHash['1']['a'] = "one"
> p pHash.keys
>
> I run this and get the result:
>
> ...undefined method `keys' for ... (NoMethodError)
>
> Do I need to dereference or something, or is this just something that doesn't
> work after all?


pHash isn't the hash-of-hashes itself, it's a Proc object
that knows how to create such a hash.

in irb:

>> pHash = lambda { Hash.new {|h,k| h[k] = pHash.call } }

=> #<Proc:0x02dc4960@(irb):1>
>> pHash.class # we can see its class is Proc

=> Proc
>> pHash.call # if we call the Proc, it does its job and creates the hash

=> {}
>> pHash[] # this is just a synonym for pHash.call

=> {}

I guess one could look at "pHash" as a factory that creates
an auto-vivifying hash.


Regards,

Bill




 
Reply With Quote
 
Phrogz
Guest
Posts: n/a
 
      08-22-2005
To be clear, what Bill is saying is that you need to use pHash.call to
create your hash, and call the Hash methods on that. Like so:

pHash = lambda { Hash.new {|h,k| h[k] = pHash.call } }

uberhash = pHash.call

uberhash['L']['a'] = "one"
p uberhash.keys #=> ["L"]
p uberhash['L'].keys #=> ["a"]
p uberhash['L'].values #=> ["one"]

 
Reply With Quote
 
William James
Guest
Posts: n/a
 
      08-22-2005
Phrogz wrote:
> To be clear, what Bill is saying is that you need to use pHash.call to
> create your hash, and call the Hash methods on that. Like so:
>
> pHash = lambda { Hash.new {|h,k| h[k] = pHash.call } }
>
> uberhash = pHash.call
>
> uberhash['L']['a'] = "one"
> p uberhash.keys #=> ["L"]
> p uberhash['L'].keys #=> ["a"]
> p uberhash['L'].values #=> ["one"]


How would you test to see if this exists?

h[9][8][7][6][5][4][3][2][1]

 
Reply With Quote
 
David A. Black
Guest
Posts: n/a
 
      08-22-2005
Hi --

On Tue, 23 Aug 2005, William James wrote:

> Phrogz wrote:
>> To be clear, what Bill is saying is that you need to use pHash.call to
>> create your hash, and call the Hash methods on that. Like so:
>>
>> pHash = lambda { Hash.new {|h,k| h[k] = pHash.call } }
>>
>> uberhash = pHash.call
>>
>> uberhash['L']['a'] = "one"
>> p uberhash.keys #=> ["L"]
>> p uberhash['L'].keys #=> ["a"]
>> p uberhash['L'].values #=> ["one"]

>
> How would you test to see if this exists?
>
> h[9][8][7][6][5][4][3][2][1]


I think it exists as soon as you refer to it. (I thought that's the
whole point But if you didn't want that to happen I guess you
could do:

if h[9][8][7][6][5][4][3][2].has_key?(1) ...


David

--
David A. Black



 
Reply With Quote
 
William James
Guest
Posts: n/a
 
      08-22-2005
David A. Black wrote:
> Hi --
>
> On Tue, 23 Aug 2005, William James wrote:
>
> > Phrogz wrote:
> >> To be clear, what Bill is saying is that you need to use pHash.call to
> >> create your hash, and call the Hash methods on that. Like so:
> >>
> >> pHash = lambda { Hash.new {|h,k| h[k] = pHash.call } }
> >>
> >> uberhash = pHash.call
> >>
> >> uberhash['L']['a'] = "one"
> >> p uberhash.keys #=> ["L"]
> >> p uberhash['L'].keys #=> ["a"]
> >> p uberhash['L'].values #=> ["one"]

> >
> > How would you test to see if this exists?
> >
> > h[9][8][7][6][5][4][3][2][1]

>
> I think it exists as soon as you refer to it. (I thought that's the
> whole point But if you didn't want that to happen I guess you
> could do:
>
> if h[9][8][7][6][5][4][3][2].has_key?(1) ...


It's not the whole point. One needs to be able to check
to see if an entry exists without changing the hash.

irb(main):002:0> h=pHash.call
=> {}
irb(main):003:0> h['foo']=999
=> 999
irb(main):005:0> if h[9][8][7][6][5][4][3][2].has_key?(1) then puts
'ok';end
=> nil
irb(main):006:0> p h
{"foo"=>999, 9=>{8=>{7=>{6=>{5=>{4=>{3=>{2=>{}}}}}}}}}

Even lowly Awk can easily do this.
-------------------------------------------------
BEGIN {
a[9,8,7,6,5,4,3,2,1] = "yes"
if ( (9,8,7,6,5,4,3,2,1) in a )
print "o.k."
if ( (0,8,7,6,5,4,3,2,1) in a )
print "not o.k."
if ( (0,8,7,6,5,4,3,2) in a )
print "not o.k."
print length(a)
}
-------------------------------------------------
Output:

o.k.
1

 
Reply With Quote
 
David A. Black
Guest
Posts: n/a
 
      08-22-2005
Hi --

On Tue, 23 Aug 2005, William James wrote:

> David A. Black wrote:
>> Hi --
>>
>> On Tue, 23 Aug 2005, William James wrote:
>>
>>> Phrogz wrote:
>>>> To be clear, what Bill is saying is that you need to use pHash.call to
>>>> create your hash, and call the Hash methods on that. Like so:
>>>>
>>>> pHash = lambda { Hash.new {|h,k| h[k] = pHash.call } }
>>>>
>>>> uberhash = pHash.call
>>>>
>>>> uberhash['L']['a'] = "one"
>>>> p uberhash.keys #=> ["L"]
>>>> p uberhash['L'].keys #=> ["a"]
>>>> p uberhash['L'].values #=> ["one"]
>>>
>>> How would you test to see if this exists?
>>>
>>> h[9][8][7][6][5][4][3][2][1]

>>
>> I think it exists as soon as you refer to it. (I thought that's the
>> whole point But if you didn't want that to happen I guess you
>> could do:
>>
>> if h[9][8][7][6][5][4][3][2].has_key?(1) ...

>
> It's not the whole point. One needs to be able to check
> to see if an entry exists without changing the hash.
>
> irb(main):002:0> h=pHash.call
> => {}
> irb(main):003:0> h['foo']=999
> => 999
> irb(main):005:0> if h[9][8][7][6][5][4][3][2].has_key?(1) then puts
> 'ok';end


I can't tell if you're saying the has_key? thing was the right
solution or that it wasn't The creation of the intermediate
hashes is desired, right?


David

--
David A. Black



 
Reply With Quote
 
William James
Guest
Posts: n/a
 
      08-22-2005
David A. Black wrote:
> Hi --
>
> On Tue, 23 Aug 2005, William James wrote:
>
> > David A. Black wrote:
> >> Hi --
> >>
> >> On Tue, 23 Aug 2005, William James wrote:
> >>
> >>> Phrogz wrote:
> >>>> To be clear, what Bill is saying is that you need to use pHash.call to
> >>>> create your hash, and call the Hash methods on that. Like so:
> >>>>
> >>>> pHash = lambda { Hash.new {|h,k| h[k] = pHash.call } }
> >>>>
> >>>> uberhash = pHash.call
> >>>>
> >>>> uberhash['L']['a'] = "one"
> >>>> p uberhash.keys #=> ["L"]
> >>>> p uberhash['L'].keys #=> ["a"]
> >>>> p uberhash['L'].values #=> ["one"]
> >>>
> >>> How would you test to see if this exists?
> >>>
> >>> h[9][8][7][6][5][4][3][2][1]
> >>
> >> I think it exists as soon as you refer to it. (I thought that's the
> >> whole point But if you didn't want that to happen I guess you
> >> could do:
> >>
> >> if h[9][8][7][6][5][4][3][2].has_key?(1) ...

> >
> > It's not the whole point. One needs to be able to check
> > to see if an entry exists without changing the hash.
> >
> > irb(main):002:0> h=pHash.call
> > => {}
> > irb(main):003:0> h['foo']=999
> > => 999
> > irb(main):005:0> if h[9][8][7][6][5][4][3][2].has_key?(1) then puts
> > 'ok';end

>
> I can't tell if you're saying the has_key? thing was the right
> solution or that it wasn't The creation of the intermediate
> hashes is desired, right?


Quote:
One needs to be able to check to see if an entry exists without
changing the hash.

Creating intermediate hashes changes the hash.

Therefore, it wasn't the right solution.

The Awk example shows that Awk can perform this check without
altering the hash in any way whatsoever, just as h.key?('foo')
doesn't alter the hash. Having to alter the hash whenever you
check for the existence of a key would be extremely crude and
ineffecient.

 
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
Is there a way to find the class methods of a class, just like'methods' finds the instance methods? Kenneth McDonald Ruby 5 09-26-2008 03:09 PM
Multidimensional hash functions Mike C++ 1 05-24-2007 01:20 PM
Multidimensional hash Todd B. Java 6 12-06-2004 12:49 PM
Aliased setter methods behave differently than other methods? Jim Cain Ruby 7 07-18-2003 04:34 PM



Advertisments
 



1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57