Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Perl > Perl Misc > Two-dim array: Strange "can't use string as ARRAY ref"

Reply
Thread Tools

Two-dim array: Strange "can't use string as ARRAY ref"

 
 
Markus Dehmann
Guest
Posts: n/a
 
      03-22-2005
I am using a two-dim hash with a string as first key, and an array as 2nd
key. But it doesn't work! Can anyone tell me what's wrong?

#!/usr/bin/perl -w
$hash{"test"}{["one", "two"]} = 42;
$hash{"test"}{["three", "four"]} = 23;
my $key = "test";
foreach(keys %{$hash{$key}}){
print "Value for $_ is $hash{$key}{$_}\n"; # ARRAY(0x804c95
# print "@$_\n"; # Can't use string ("ARRAY(0x804c95") as an ARRAY ref
}

The output is:
Value for ARRAY(0x804c95 is 23

Why does it print only *one* value? Why can't I dereference
the array ref $_?

Thanks!

 
Reply With Quote
 
 
 
 
Eric Schwartz
Guest
Posts: n/a
 
      03-22-2005
Markus Dehmann <(E-Mail Removed)> writes:
> I am using a two-dim hash with a string as first key, and an array as 2nd
> key. But it doesn't work! Can anyone tell me what's wrong?


You can't use an array as a hash key. The very first paragraph of
perldata says:

Hashes are unordered collections of scalar values indexed by
their associated string key.

So when you try to index a hash with an array like this:

> $hash{"test"}{["one", "two"]} = 42;


what's happening instead is that ["one","two"] is being stringified
into something like ARRAY(0x804c95, and that string is what your
second-level hash is being subscripted by.
> The output is:
> Value for ARRAY(0x804c95 is 23
>
> Why does it print only *one* value? Why can't I dereference
> the array ref $_?


Because it's not an array ref anymore, it's a string. Only strings
can be stored as the keys of hashes-- the values can be anything you
like.

-=Eric
--
Come to think of it, there are already a million monkeys on a million
typewriters, and Usenet is NOTHING like Shakespeare.
-- Blair Houghton.
 
Reply With Quote
 
 
 
 
Sherm Pendley
Guest
Posts: n/a
 
      03-22-2005
Eric Schwartz wrote:

> You can't use an array as a hash key.


It's not impossible to use array refs as keys, but it does require some
additional steps that aren't needed when you use strings as keys. Have a
look at Tie::RefHash. (It's a core module in my copy of 5.8.1 - I don't
know about earlier.)

sherm--

--
Cocoa programming in Perl: http://camelbones.sourceforge.net
Hire me! My resume: http://www.dot-app.org
 
Reply With Quote
 
Gunnar Hjalmarsson
Guest
Posts: n/a
 
      03-22-2005
Markus Dehmann wrote:
> I am using a two-dim hash with a string as first key, and an array as 2nd
> key.


No you are not. A hash key cannot be an array.

But it doesn't work! Can anyone tell me what's wrong?
>
> #!/usr/bin/perl -w
> $hash{"test"}{["one", "two"]} = 42;
> $hash{"test"}{["three", "four"]} = 23;


Try this:

use Data:umper;
print Dumper \%hash;

> my $key = "test";
> foreach(keys %{$hash{$key}}){
> print "Value for $_ is $hash{$key}{$_}\n"; # ARRAY(0x804c95
> # print "@$_\n"; # Can't use string ("ARRAY(0x804c95") as an ARRAY ref
> }
>
> The output is:
> Value for ARRAY(0x804c95 is 23
>
> Why does it print only *one* value?


Because there is only one value.

> Why can't I dereference the array ref $_?


See Eric's answer about that.

--
Gunnar Hjalmarsson
Email: http://www.gunnar.cc/cgi-bin/contact.pl
 
Reply With Quote
 
Tad McClellan
Guest
Posts: n/a
 
      03-22-2005
Markus Dehmann <(E-Mail Removed)> wrote:

> I am using a two-dim hash with a string as first key, and an array as 2nd
> key.



You cannot have arrays as keys in Perl hashes.


> But it doesn't work!



What were you hoping that it would do?


> Can anyone tell me what's wrong?



You are trying to create an impossible data structure.

If you had told us what you really want, then we would have a
chance of showing you how to refactor your data structure.


> #!/usr/bin/perl -w
> $hash{"test"}{["one", "two"]} = 42;



Hash keys are forced to be strings.

If you give it an array ref as a hash key, you will get a stringified
representation of the reference, which can no longer be used to
access the array.


> $hash{"test"}{["three", "four"]} = 23;



Do you want the 2nd level hash to have 4 key/value pairs in it?

$hash{test}{one} = 42;
$hash{test}{two} = 42;
$hash{test}{three} = 23;
$hash{test}{four} = 23;

or, by using a "hash slice":

@hash{ qw/ one two three four / } = (42, 42, 23, 23);


If you wanted something else, try telling us what that something else is.


> my $key = "test";
> foreach(keys %{$hash{$key}}){
> print "Value for $_ is $hash{$key}{$_}\n"; # ARRAY(0x804c95
> # print "@$_\n"; # Can't use string ("ARRAY(0x804c95") as an ARRAY ref
> }
>
> The output is:
> Value for ARRAY(0x804c95 is 23
>
> Why does it print only *one* value?



Because there is only one key ("test") in the hash, your 2nd
assignment stomped over the value of the 1st assignment.


> Why can't I dereference
> the array ref $_?



Because it is NOT an array ref, it is a string.


--
Tad McClellan SGML consulting
http://www.velocityreviews.com/forums/(E-Mail Removed) Perl programming
Fort Worth, Texas
 
Reply With Quote
 
Gunnar Hjalmarsson
Guest
Posts: n/a
 
      03-22-2005
Sherm Pendley wrote:
> Eric Schwartz wrote:
>> You can't use an array as a hash key.

>
> It's not impossible to use array refs as keys, but it does require some
> additional steps that aren't needed when you use strings as keys. Have a
> look at Tie::RefHash.


While giving Eric right, "perldoc perlref" mentions that Tie::RefHash
provides a *workaround*. The distinction seems to be important to
understand this limitation with Perl hashes.

--
Gunnar Hjalmarsson
Email: http://www.gunnar.cc/cgi-bin/contact.pl
 
Reply With Quote
 
Eric Amick
Guest
Posts: n/a
 
      03-23-2005
On Tue, 22 Mar 2005 17:31:39 -0500, Markus Dehmann
<(E-Mail Removed)> wrote:

>I am using a two-dim hash with a string as first key, and an array as 2nd
>key. But it doesn't work! Can anyone tell me what's wrong?


>
>#!/usr/bin/perl -w
>$hash{"test"}{["one", "two"]} = 42;
>$hash{"test"}{["three", "four"]} = 23;


Hash keys are strings, so the array reference is converted to a string.
You need to look at the Tie::RefHash module, which I believe is a core
module, to do what you're after.

--
Eric Amick
Columbia, MD
 
Reply With Quote
 
Brian McCauley
Guest
Posts: n/a
 
      03-23-2005


Eric Amick wrote:
> On Tue, 22 Mar 2005 17:31:39 -0500, Markus Dehmann
> <(E-Mail Removed)> wrote:
>
>
>>I am using a two-dim hash with a string as first key, and an array as 2nd
>>key. But it doesn't work! Can anyone tell me what's wrong?

>
>
>>#!/usr/bin/perl -w
>>$hash{"test"}{["one", "two"]} = 42;
>>$hash{"test"}{["three", "four"]} = 23;

>
>
> Hash keys are strings, so the array reference is converted to a string.
> You need to look at the Tie::RefHash module, which I believe is a core
> module, to do what you're after.


But if using Tie::RefHash you can't look up an element using
$hash{"test"}{["three", "four"]} because the ["three", "four"] creates a
new array. It may have the same content as the array that's used as a
key but it is not the same array.

 
Reply With Quote
 
Markus Dehmann
Guest
Posts: n/a
 
      03-23-2005
Tad McClellan wrote:

> Markus Dehmann <(E-Mail Removed)> wrote:
>
>> I am using a two-dim hash with a string as first key, and an array as 2nd
>> key.

>
>
> You cannot have arrays as keys in Perl hashes.
>
>> But it doesn't work!

>
> What were you hoping that it would do?


Thanks for all your comments. Now I know why it didn't work.

> If you had told us what you really want, then we would have a
> chance of showing you how to refactor your data structure.
>
> Do you want the 2nd level hash to have 4 key/value pairs in it?
>
> $hash{test}{one} = 42;
> $hash{test}{two} = 42;
> $hash{test}{three} = 23;
> $hash{test}{four} = 23;
>
> or, by using a "hash slice":
>
> @hash{ qw/ one two three four / } = (42, 42, 23, 23);
>
> If you wanted something else, try telling us what that something else is.


If you know C++ and STL you'll understand this data structure:

map< string, map< set<string>, double > > myHash;

That's what I wanted in Perl.

I understand that I could use Tie::RefHash. But I now used another
workaround:

$hash{test}{"one two"} = 42;
$hash{test}{"three four"} = 23;

Instead of the array as a 2nd key, I use a string "one two" that I just
split when I work with it.

Markus





 
Reply With Quote
 
Tad McClellan
Guest
Posts: n/a
 
      03-23-2005
Markus Dehmann <(E-Mail Removed)> wrote:
> Tad McClellan wrote:
>> Markus Dehmann <(E-Mail Removed)> wrote:
>>
>>> I am using a two-dim hash with a string as first key, and an array as 2nd
>>> key.



>> If you wanted something else, try telling us what that something else is.



> But I now used another
> workaround:
>
> $hash{test}{"one two"} = 42;
> $hash{test}{"three four"} = 23;
>
> Instead of the array as a 2nd key, I use a string "one two" that I just
> split when I work with it.



Maybe you want a _3_ dimensional data structure?

$hash{test}{one}{two} = 42;


--
Tad McClellan SGML consulting
(E-Mail Removed) Perl programming
Fort Worth, Texas
 
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
Strange behavior of "use if" (a conditional "use" with the if module) David Filmer Perl Misc 2 03-29-2013 01:19 AM
Re: Strange array.array performance Maxim Khitrov Python 5 03-12-2009 12:48 AM
Strange array.array performance Maxim Khitrov Python 0 02-19-2009 06:52 PM
Strange question: Convert string to array name kenbo Ruby 8 02-20-2007 11:23 AM
'System.String[]' from its string representation 'String[] Array' =?Utf-8?B?UmFqZXNoIHNvbmk=?= ASP .Net 0 05-04-2006 04:29 PM



Advertisments