Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Ruby > x=[]; x[:bla][:some_key] does not work?

Reply
Thread Tools

x=[]; x[:bla][:some_key] does not work?

 
 
forum@josh.ch
Guest
Posts: n/a
 
      11-03-2007
Hi all

PHP lets me easily create multidimensional hashes using the following
syntax:

x = array();
x["bla"]["some_key"] = true;

Is Ruby not capable of doing this?

x = []
x[:bla][:some_key] = true

gives me a nil error!

What wrong here?

Thanks Josh
--
Posted via http://www.ruby-forum.com/.

 
Reply With Quote
 
 
 
 
dblack@rubypal.com
Guest
Posts: n/a
 
      11-03-2007
Hi --

On Sun, 4 Nov 2007, Joshua Muheim wrote:

> Hi all
>
> PHP lets me easily create multidimensional hashes using the following
> syntax:
>
> x = array();
> x["bla"]["some_key"] = true;
>
> Is Ruby not capable of doing this?
>
> x = []
> x[:bla][:some_key] = true
>
> gives me a nil error!


Are you sure it's not giving you a "Symbol as array index" error?

> What wrong here?


A couple of things. You're indexing an array with a symbol, but you
have to use an integer. You're also expecting a non-existent array
element to be something other than nil, but it isn't:

a = []
a[1] # nil

You're then trying (or would be, if you used an integer instead of
:bla) to call the method [] on nil, and nil has no such method.
(Remember that the index syntax, a[n], is actually a method call:
a.[](n).)


David

--
Upcoming training by David A. Black/Ruby Power and Light, LLC:
* Advancing With Rails, Edison, NJ, November 6-9
* Advancing With Rails, Berlin, Germany, November 19-22
* Intro to Rails, London, UK, December 3-6 (by Skills Matter)
See http://www.rubypal.com for details!

 
Reply With Quote
 
 
 
 
forum@josh.ch
Guest
Posts: n/a
 
      11-03-2007
Ups I'm sorry, I messed things up because PHP uses [] for both arrays
and hashes.

x = array();
x["bla"]["some_key"] = true;

Is Ruby not capable of doing this?

x = {}
x[:bla][:some_key] = true
--
Posted via http://www.ruby-forum.com/.

 
Reply With Quote
 
jan.svitok@gmail.com
Guest
Posts: n/a
 
      11-03-2007
On 11/3/07, Joshua Muheim <(E-Mail Removed)> wrote:
> Hi all
>
> PHP lets me easily create multidimensional hashes using the following
> syntax:
>
> x = array();
> x["bla"]["some_key"] = true;
>
> Is Ruby not capable of doing this?
>
> x = []
> x[:bla][:some_key] = true
>
> gives me a nil error!


As David said, if you want to create hashes, you have to create Hashes

Then, you can tell Hash.new what is the default value, so you can
create hash, that will contain by default empty hashes:

x = Hash.new { Hash.new }

This will add an "automatic" two level hash. I don't know quickly how
to make this indefinitly deep, you can at least repeat the pattern.

Please note that it is not enough to write Hash.new { {} } as the
inner will create one particular Hash instance, that all keys will
reference. You need Hash.new to create a new hash for each key.

Jano

 
Reply With Quote
 
lionel-subscription@bouton.name
Guest
Posts: n/a
 
      11-03-2007
Joshua Muheim wrote:
> Ups I'm sorry, I messed things up because PHP uses [] for both arrays
> and hashes.
>
> x = array();
> x["bla"]["some_key"] = true;
>
> Is Ruby not capable of doing this?
>
> x = {}
> x[:bla][:some_key] = true
>

For a 2-dimensional Hash you can use:

h = Hash.new({})

See the documentation of the initialize method of the Hash class. Here
it basically tells the object to use a default value (an empty hash) for
uninitialized keys.

Lionel

 
Reply With Quote
 
lionel-subscription@bouton.name
Guest
Posts: n/a
 
      11-03-2007
Jano Svitok wrote:
>
> Please note that it is not enough to write Hash.new { {} } as the
> inner will create one particular Hash instance, that all keys will
> reference. You need Hash.new to create a new hash for each key.
>


Ooopps, my bad.

Lionel

 
Reply With Quote
 
sepp2k@googlemail.com
Guest
Posts: n/a
 
      11-03-2007
Joshua Muheim wrote:
> PHP lets me easily create multidimensional hashes[...]
> Is Ruby not capable of doing this?
>
> x = []


That's an array. A hash would be x={}

> x[:bla][:some_key] = true
>
> gives me a nil error!


The code above should give you a different error. If you use {} it should give
you a nil error because x[:bla] would return nil and nil doesn't have a method
[].
To fix that you have to make x return a hash for non-existant keys. That would
work as such:
x = Hash.new {|h,k| h[k] = Hash.new}
x[:bla][:some_key] = true

Or if you want an arbitrary amount of nesting:

blk = lambda {|h,k| h[k] = Hash.new(&blk)}
x = Hash.new(&blk)
x[:la][:li][:lu][:chunky][:bacon][:foo] = "bar"


HTH,
Sebastian
--
Jabber: http://www.velocityreviews.com/forums/(E-Mail Removed)
ICQ: 205544826

 
Reply With Quote
 
sepp2k@googlemail.com
Guest
Posts: n/a
 
      11-03-2007
Lionel Bouton wrote:
> For a 2-dimensional Hash you can use:
>
> h = Hash.new({})


That won't result in the behaviour most people would expect from a
2-dimensional hash:
>> h = Hash.new({})

=> {}
>> h[:a][:foo] = "bar"

=> "bar"
>> h[:a]

=> {:foo=>"bar"}
>> h

=> {}
>> h[:b][:chunky] = "bacon"

=> "bacon"
>> h[:b]

=> {:chunky=>"bacon", :foo=>"bar"}
>> h[:c]

=> {:chunky=>"bacon", :foo=>"bar"}
>> h

=> {}

You want to a) use the block-form of Hash.new to not use the same instance of
a hash everytime and b) assign the new Hash instead of just returning it.


--
Jabber: (E-Mail Removed)
ICQ: 205544826

 
Reply With Quote
 
dblack@rubypal.com
Guest
Posts: n/a
 
      11-03-2007
Hi --

On Sun, 4 Nov 2007, Jano Svitok wrote:

> On 11/3/07, Joshua Muheim <(E-Mail Removed)> wrote:
>> Hi all
>>
>> PHP lets me easily create multidimensional hashes using the following
>> syntax:
>>
>> x = array();
>> x["bla"]["some_key"] = true;
>>
>> Is Ruby not capable of doing this?
>>
>> x = []
>> x[:bla][:some_key] = true
>>
>> gives me a nil error!

>
> As David said, if you want to create hashes, you have to create Hashes
>
> Then, you can tell Hash.new what is the default value, so you can
> create hash, that will contain by default empty hashes:
>
> x = Hash.new { Hash.new }
>
> This will add an "automatic" two level hash. I don't know quickly how
> to make this indefinitly deep, you can at least repeat the pattern.
>
> Please note that it is not enough to write Hash.new { {} } as the
> inner will create one particular Hash instance, that all keys will
> reference. You need Hash.new to create a new hash for each key.


That's not quite right. The only-one-object thing is when you do this:

h = Hash.new({})

If you use a block, it gets executed each time -- so in your example,
a new hash would get created.

However, it's important to remember that what you're setting is the
default value (or behavior) for *non-existent* keys. So if you do:

h = Hash.new { {} }
a = h[1]

a is now a hash, but h still has no keys.

The block is automatically passed the hash itself, and the key:

h = Hash.new {|hash,key| # do stuff with hash and key }

and you can use that fact to actually add the key to the hash.


David

--
Upcoming training by David A. Black/Ruby Power and Light, LLC:
* Advancing With Rails, Edison, NJ, November 6-9
* Advancing With Rails, Berlin, Germany, November 19-22
* Intro to Rails, London, UK, December 3-6 (by Skills Matter)
See http://www.rubypal.com for details!

 
Reply With Quote
 
bbxx789_05ss@yahoo.com
Guest
Posts: n/a
 
      11-03-2007
Joshua Muheim wrote:
> Hi all
>
> PHP lets me easily create multidimensional hashes using the following
> syntax:
>
> x = array();
> x["bla"]["some_key"] = true;
>
> Is Ruby not capable of doing this?
>
> x = []
> x[:bla][:some_key] = true
>
> gives me a nil error!
>


x = []
x[:blah][:some_key] = true

--output:--
`[]': Symbol as array index (TypeError)
from r5test.rb:2

In ruby, array indexes must be non-negative integers-not symbols, not
strings, not floats...err this actually 'works':

x = []
x[3.5] = true
puts x[3.5]

--output:--
true

But, I think that ruby must convert the float to an int. However, this
works:

puts x.values_at(3.5)

--output:--
true

But, then so does this:

puts x.values_at(3)

--output:--
true

So, I can't really figure out a way to prove that the index value can't
be a float. Anyway...


To create nested hashes you can do this:

x = {}
x['a'] = 10
p x

x[:bla] = {1=>10, 2=>20}
p x

--output:--
{"a"=>10}
{"a"=>10, :bla=>{1=>10, 2=>20}}


Writing this is problematic, though:

x = {}
x[:bla][:some_key] = true

--output:--
undefined method `[]=' for nil:NilClass (NoMethodError)

That is equivalent to:

x = {}
lookup1 = x[:bla]
lookup1[:some_key] = true

and when you lookup a non-existent key for a hash, it returns nil. As
a result, lookup1 is assigned nil.

But in ruby you can make hashes to return whatever you want when you
lookup a non-existent key. You do that by specifying what you want
returned in the Hash constructor:

x = Hash.new {|hash, key| hash[key] = {} }
x[:bla][:some_key] = true
p x

--output:--
{:bla=>{:some_key=>true}}





--
Posted via http://www.ruby-forum.com/.

 
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
'' is not a valid name. Make sure that it does not include invalid characters or punctuation and that it is not too long. rote ASP .Net 2 01-23-2008 03:07 PM
PC does not start and does not turn off sean Computer Support 3 12-28-2006 10:37 AM
CS0234 Global does not exist ... but it genuinely does Bill Johnson ASP .Net 0 07-08-2005 06:34 PM
Power button does not turn OFF? New power supply does not help! win2k lbbss Computer Support 0 01-06-2005 04:03 PM
Webservice works once and then DOES NOT seem to work even though program does not crash Phi! ASP .Net Web Services 1 04-23-2004 08:42 AM



Advertisments