hash value initializarion to zero ...

M

martin

This is probably a simpel question, I am trying to intialize a large
hash, the keys are single word strings and the values are numeric.
I am wondering if there is a simple way to use two arrays to assign to
values and keys respectively, as opposed to the usual means of

let's say

my %citieshash {'key1', value1, 'key2', value2, ........}



if I have a large hash of 100 entries, let say this becomes awkward
specially if I want to set all values to zero, initially.

I tried %cities = ( );


and then used a loop to scan from a file the keys, it works fine if all
city names are present , but if not all keys/cities are present, and I
want to do addition of values with += the compiler starts complaining.
Is there a single shot approach to zero initialization and also to
setting key values using an existing array.

something like

(keys %citieshash) = @some_array <-- I know this one does not work

Thanks.
 
X

xhoster

martin said:
This is probably a simpel question, I am trying to intialize a large
hash, the keys are single word strings and the values are numeric.
I am wondering if there is a simple way to use two arrays to assign to
values and keys respectively, as opposed to the usual means of

let's say

my %citieshash {'key1', value1, 'key2', value2, ........}

Er, let's say something else!
if I have a large hash of 100 entries, let say this becomes awkward
specially if I want to set all values to zero, initially.

I tried %cities = ( );

and then used a loop to scan from a file the keys, it works fine if all
city names are present , but if not all keys/cities are present, and I
want to do addition of values with += the compiler starts complaining.

The compiler shouldn't complain if the missing value is on the left side
of the +=. If it is on the right, then you could just use something like
$foo+=$hash{$_}||0
Is there a single shot approach to zero initialization and also to
setting key values using an existing array.

something like

(keys %citieshash) = @some_array <-- I know this one does not work

my %citieshash = map {$_, 0} @some_array;

Xho
 
J

John W. Krahn

martin said:
This is probably a simpel question, I am trying to intialize a large
hash, the keys are single word strings and the values are numeric.
I am wondering if there is a simple way to use two arrays to assign to
values and keys respectively,

Yes, it's called a hash slice:

@hash{ @keys } = @values;
as opposed to the usual means of

let's say

my %citieshash {'key1', value1, 'key2', value2, ........}

You could do something like this:

my %citieshash = map { $keys{ $_ }, $values{ $_ } } 0 .. $#keys;
if I have a large hash of 100 entries, let say this becomes awkward
specially if I want to set all values to zero, initially.

I tried %cities = ( );

If the hash already has keys:

$_ = 0 for %hash;

Or:

@hash{ @keys } = ( 0 ) x @keys;

Or:

my %hash = map { $_ => 0 } @keys;
and then used a loop to scan from a file the keys, it works fine if all
city names are present , but if not all keys/cities are present, and I
want to do addition of values with += the compiler starts complaining.

It shouldn't.

$ perl -le'
use warnings;
use strict;
my %hash;
$hash{ key } += 10;
print $hash{ key };
'
10
Is there a single shot approach to zero initialization and also to
setting key values using an existing array.

See above.


John
 
J

John W. Krahn

martin said:
This is probably a simpel question, I am trying to intialize a large
hash, the keys are single word strings and the values are numeric.
I am wondering if there is a simple way to use two arrays to assign to
values and keys respectively,

Yes, it's called a hash slice:

@hash{ @keys } = @values;
as opposed to the usual means of

let's say

my %citieshash {'key1', value1, 'key2', value2, ........}

You could do something like this:

my %citieshash = map { $keys[ $_ ], $values[ $_ ] } 0 .. $#keys;
if I have a large hash of 100 entries, let say this becomes awkward
specially if I want to set all values to zero, initially.

I tried %cities = ( );

If the hash already has keys:

$_ = 0 for %hash;

Or:

@hash{ @keys } = ( 0 ) x @keys;

Or:

my %hash = map { $_ => 0 } @keys;
and then used a loop to scan from a file the keys, it works fine if all
city names are present , but if not all keys/cities are present, and I
want to do addition of values with += the compiler starts complaining.

It shouldn't.

$ perl -le'
use warnings;
use strict;
my %hash;
$hash{ key } += 10;
print $hash{ key };
'
10
Is there a single shot approach to zero initialization and also to
setting key values using an existing array.

See above.


John
 
D

DJ Stunks

martin said:
Is there a single shot approach to zero initialization and also to
setting key values using an existing array.

I'm not totally clear on what you're up to, but I hope this helps:

C:\tmp>cat -n tmp2.pl
1 #!/usr/bin/perl
2
3 use strict;
4 use warnings;
5
6 my @array = map { "key$_" } 0..9;
7
8 # Initialize hash to 0's
9 my %cities = map { $_ => 0 } @array;
10
11 # Populate some members
12 for my $key ( map { "key$_" } (6,2,7) ) {
13 $cities{$key} = int rand 100;
14 }
15
16 # Print resulting hash
17 for my $key (sort keys %cities) {
18 printf "%5s => %5s\n", $key, $cities{$key};
19 }
20
21 __END__

C:\tmp>tmp2.pl
key0 => 0
key1 => 0
key2 => 23
key3 => 0
key4 => 0
key5 => 0
key6 => 13
key7 => 39
key8 => 0
key9 => 0

-jp
 
A

Anno Siegel

John W. Krahn said:
martin wrote:
[...]
if I have a large hash of 100 entries, let say this becomes awkward
specially if I want to set all values to zero, initially.

I tried %cities = ( );

If the hash already has keys:

$_ = 0 for %hash;

That would have to be

$_ = 0 for values %hash;

Anno
 
P

Paul Lalli

Anno said:
That would have to be

$_ = 0 for values %hash;

Did you try it?

perl -MData::Dumper -e'
my %h = (one=>1, two=>2, three=>3);
$_ = 0 for %h;
print Dumper(\%h);
'
$VAR1 = {
'one' => 0,
'three' => 0,
'two' => 0
};

Looks like it works just fine to me. I can only assume this is due to
the rather odd properties of a hash that the values returned are
aliases, while the keys are copies.

Paul Lalli
 
A

Anno Siegel

Paul Lalli said:
Did you try it?

No. I simply assumed he'd forgotten "values".
perl -MData::Dumper -e'
my %h = (one=>1, two=>2, three=>3);
$_ = 0 for %h;
print Dumper(\%h);
'
$VAR1 = {
'one' => 0,
'three' => 0,
'two' => 0
};

Looks like it works just fine to me. I can only assume this is due to
the rather odd properties of a hash that the values returned are
aliases, while the keys are copies.

I'd say "happens to work" instead of "works just fine". It relies on
an obscure effect, and it does twice the necessary number of assignments.
I'd still consider it an error in non-obfuscated code.

Anno
 
U

Uri Guttman

PL> Looks like it works just fine to me. I can only assume this is due to
PL> the rather odd properties of a hash that the values returned are
PL> aliases, while the keys are copies.

you should know better about hash keys. you can never change an existing
key as it would require a hashing of the new key. so that means
modifying a key it is just an assignment to a hash slot. so there is no
win to making the key modifyable. on the otherhand, the values are just
normal SV's which means you can take refs to the, alias them in values
(and foreach values also aliases) and change them on the fly.

and slices and x work well here too:

@hash{ keys %hash } = (0) x keys %hash ;

you would think this also should work if values just aliased the hash
values:

perl -le '%h=(1,2,3,4) ;(values %h) = (0,0) ; print %h'
Can't modify values in list assignment at -e line 1, near ") ;"

uri
 
P

Paul Lalli

Uri said:
PL> Looks like it works just fine to me. I can only assume this is due to
PL> the rather odd properties of a hash that the values returned are
PL> aliases, while the keys are copies.

you should know better about hash keys. you can never change an existing
key as it would require a hashing of the new key. so that means
modifying a key it is just an assignment to a hash slot. so there is no
win to making the key modifyable. on the otherhand, the values are just
normal SV's which means you can take refs to the, alias them in values
(and foreach values also aliases) and change them on the fly.

Thank you for that explanation, Uri. Much appreciated.

Paul Lalli
 
B

Brian McCauley

Paul said:
Did you try it?

Trying it is not always sufficient.

ISTR that somewhere in the Perl documentation there was at one time an
explicit warning that the fact that hash keys are not modifyable is
subject to change in future versions of Perl. I don't think this is
still there and so I'd be supprised if the keys were now ever to became
modifyable.

However by rights John's code should thow an "attempt to modify
read-only value" and I'd be only slightly supprised if in some future
version of Perl it actually did.
 
C

Charles DeRykus

Uri said:
PL> Looks like it works just fine to me. I can only assume this is due to
PL> the rather odd properties of a hash that the values returned are
PL> aliases, while the keys are copies.

you should know better about hash keys. you can never change an existing
key as it would require a hashing of the new key. so that means
modifying a key it is just an assignment to a hash slot. so there is no
win to making the key modifyable. on the otherhand, the values are just
normal SV's which means you can take refs to the, alias them in values
(and foreach values also aliases) and change them on the fly.

and slices and x work well here too:

@hash{ keys %hash } = (0) x keys %hash ;

you would think this also should work if values just aliased the hash
values:

perl -le '%h=(1,2,3,4) ;(values %h) = (0,0) ; print %h'
Can't modify values in list assignment at -e line 1, near ") ;"

Seems like the cleaner, faster idiom would be $_ = 0 for values %h
instead of $_ = 0 for %h (even with 6 more keystokes) since the key
assignments in the later are just throwaway's.
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,482
Members
44,901
Latest member
Noble71S45

Latest Threads

Top