Combine hash declaration/assignment into single statement?

U

usenet

It is often possible to declare and assign a variable in a single
statement, such as:
my $foo = 'bar';
or
my @foo = qw{bar baz};

Is it possible to do this in a single statement (under strict):

my %character_value;
@character_value{'a'..'z'} = (1..26);


Thanks!
 
U

Uri Guttman

u> It is often possible to declare and assign a variable in a single
u> statement, such as:
u> my $foo = 'bar';
u> or
u> my @foo = qw{bar baz};

u> Is it possible to do this in a single statement (under strict):

u> my %character_value;
u> @character_value{'a'..'z'} = (1..26);

not with that data in one statment. but there are many variations which
can be used.

first, you may already have the keys in an array for various reasons
(ordering, read from somewhere else, etc.). then you can use map to
assign integer values:

my @chars = ( 'a' .. 'z' ) ;
my %foo = map { $chars[$_ - 1] => $_ } 1 .. @chars ;

if you don't mind destroying @chars (say a copy is used) this works:

my %foo = map { shift @chars => $_ } 1 .. @chars ;

that can be used to merge two arrays if either one can be destroyed:

my %foo = map { shift @keys => $_ } @values ;
my %foo = map { $_ => shift @values } @keys ;

or if you just wanted the keys to exist (for checking if a string is in
a set):

my %foo = map { $_ => undef } @chars ;

uri
 
R

Rick Scott

([email protected] uttered:)
It is often possible to declare and assign a variable in a single
statement, such as:
my $foo = 'bar';
or
my @foo = qw{bar baz};

Is it possible to do this in a single statement (under strict):

my %character_value;
@character_value{'a'..'z'} = (1..26);

My first thought was to do this:

#!/usr/bin/perl

use warnings;
use strict;
use List::MoreUtils qw(zip);

my %character_value = zip('a'..'z', 1..26);

But as it turns out, there is a subtle distinction between lists and
arrays of which I was not previously aware, and List::MoreUtils::zip
needs arrays:

Type of arg 1 to List::MoreUtils::mesh must be array (not null
operation) at foo.pl line 14, near "26)"
Type of arg 2 to List::MoreUtils::mesh must be array (not null
operation) at foo.pl line 14, near "26)"


It's not a single statement, but (in addition to any of Uri's
excellent suggestions) you can still do this:

#!/usr/bin/perl

use warnings;
use strict;
use List::MoreUtils qw(zip);

my @keys = 'a'..'z';
my @values = 1..26;

my %character_value = zip(@keys, @values);




Rick
 
S

Sisyphus

Rick Scott said:
([email protected] uttered:)

My first thought was to do this:

#!/usr/bin/perl

use warnings;
use strict;
use List::MoreUtils qw(zip);

my %character_value = zip('a'..'z', 1..26);

But as it turns out, there is a subtle distinction between lists and
arrays of which I was not previously aware, and List::MoreUtils::zip
needs arrays:

I think it's the anonymity that trips it up. If you provide anonymous arrays
as the arguments:

my %character_value = zip(('a' .. 'z'), (1 .. 26));

then you still get the same error.

Cheers,
Rob
 
U

Uri Guttman

S> I think it's the anonymity that trips it up. If you provide anonymous arrays
S> as the arguments:

S> my %character_value = zip(('a' .. 'z'), (1 .. 26));

S> then you still get the same error.

that code is the exact same thing as the above code. in both cases zip
sees a single list of values. your extra parens did nothing and they
aren't anon arrays. you need [] for that. my guess (easily verified by
the docs or code) is that zip has a prototype looking for @ (possibly
\@). lists can only be passed to a sub as the last argument anyhow. you
can never pass 2 lists to a sub.

uri
 
L

Lukas Mai

(e-mail address removed) schrob:
Is it possible to do this in a single statement (under strict):

my %character_value;
@character_value{'a'..'z'} = (1..26);

Not really, but there's

my %character_value = map +($_ => ord($_) - ord('a') + 1), 'a' .. 'z';

HTH, Lukas
 
S

Sisyphus

Uri Guttman said:
S> I think it's the anonymity that trips it up. If you provide anonymous arrays
S> as the arguments:

S> my %character_value = zip(('a' .. 'z'), (1 .. 26));

S> then you still get the same error.
..
..
your extra parens did nothing and they
aren't anon arrays. you need [] for that.

Oh ... I've always thought that the square brackets created a "reference to
a list" - and that a "reference to a list" and an "anonymous array" are
different things. (You can see from the above what I thought an anonymous
array was.) Thanks for the correction.

Cheers,
Rob
 
R

Rick Scott

(Uri Guttman said:
S> I think it's the anonymity that trips it up. If you provide
S> anonymous arrays as the arguments:

S> my %character_value = zip(('a' .. 'z'), (1 .. 26));

S> then you still get the same error.

that code is the exact same thing as the above code. in both cases
zip sees a single list of values. your extra parens did nothing
and they aren't anon arrays. you need [] for that. my guess
(easily verified by the docs or code) is that zip has a prototype
looking for @ (possibly \@).

Exactly right:

# List::MoreUtils.pm -- zip is aliased to mesh
sub mesh
(\@\@;\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@) {
my $max = -1;
$max < $#$_ && ($max = $#$_) for @_;

map { my $ix = $_; map $_->[$ix], @_; } 0..$max;
}

Funny; for some reason I'd been labouring under the mistaken
impression that function prototypes were practically ornamental.
Obviously time for more study.




Rick
 
S

Samwyse

Lukas said:
(e-mail address removed) schrob:



Not really, but there's

my %character_value = map +($_ => ord($_) - ord('a') + 1), 'a' .. 'z';

Just to be pedantic, all of this only works under character encodings
(like ASCII) where 'a'..'z' are contigious values; under EBCDIC, for
instance, 'a'..'z' is a list of 40 values, some of which are not
alphabetic. The expression (grep/\w/,'a'..'z') will get you back down
to 26 values.
 
P

Paul Lalli

Sisyphus said:
Oh ... I've always thought that the square brackets created a "reference to
a list" - and that a "reference to a list" and an "anonymous array" are
different things. (You can see from the above what I thought an anonymous
array was.) Thanks for the correction.

There's no such thing as a reference to a list. [1]
You can have a reference to an array.
That array can be named, or it can be anonymous.

Once you have your reference, you can dereference it. Thus giving you
an array.

my @array = (1..5); # a named array;
my $a_ref = \@array; # a reference to a named array.
my $a_ref2 = [ 1.. 5 ]; # a reference to an anonymous array.

print @$a_ref; #the same array as the named array @array.
print @$a_ref2; #the anonymous array referenced by $a_ref2

@$a_ref2 is an anonymous array, because it does not have a name. It
has only a reference. The only way of using it is by dereferencing its
reference.

Paul Lalli

[1]. The syntax that you might expect to create such a thing:
\($foo, $bar, $baz)
actually creates a list of references, not a reference to a list. That
is, it creates:
(\$foo, \$bar, \$baz);
(in list context, anyway. In scalar context, it creates each
reference, but returns only the last one).
 
A

Anno Siegel

Rick Scott said:
([email protected] uttered:)

My first thought was to do this:

#!/usr/bin/perl

use warnings;
use strict;
use List::MoreUtils qw(zip);

my %character_value = zip('a'..'z', 1..26);

But as it turns out, there is a subtle distinction between lists and
arrays of which I was not previously aware, and List::MoreUtils::zip
needs arrays:

Then give it arrays:

my %character_value = zip @{ [ 'a' .. 'z'] }, @{ [ 1 .. 26] };

or, overriding the prototype:

my %character_value = &zip( [ 'a' .. 'z'], [ 1 .. 26]);

Anno
 
D

DJ Stunks

Anno said:
or, overriding the prototype:

my %character_value = &zip( [ 'a' .. 'z'], [ 1 .. 26]);

:) very nice.

I wasn't totally clear on the role of & previously...

-jp
 
R

Rick Scott

(Anno Siegel said:
Rick Scott said:
my %character_value = zip('a'..'z', 1..26);

But as it turns out, there is a subtle distinction between lists
and arrays of which I was not previously aware, and
List::MoreUtils::zip needs arrays ...

Then give it arrays:

my %character_value = zip @{ [ 'a' .. 'z'] }, @{ [ 1 .. 26] };

or, overriding the prototype:

my %character_value = &zip( [ 'a' .. 'z'], [ 1 .. 26]);

That's the syntax I was looking for but couldn't seem to figure out.
Thanks Anno.




Rick
 
U

Uri Guttman

DS> Anno Siegel said:
or, overriding the prototype:

my %character_value = &zip( [ 'a' .. 'z'], [ 1 .. 26]);

DS> :) very nice.

DS> I wasn't totally clear on the role of & previously...

i was going to skip this but now that you decided it was a good idea, i
have to comment. & has several uses and almost all are poor to bad. the
simplest and safest is that you can call subs without () or predeclaring
them (via use subs or sub foo). another thing it does which is very
nasty is to call subs like &foo ;. that passes the currently @_ to the
called sub so this can lead to nasty bugs where you don't deal properly
with @_. the other thing it does is shut off prototypes as anno
shows. but if there was a reason for prototypes (in this case taking two
array args) then defeating that can be nasty. it smacks of breaking
encapsulation as well. i find it troublesome that a prototype of \@
won't allow an array ref to be passed instead of a real array. well p6
will handle that correctly.

also i tried to install List::MoreUtils to play with zip but when it
started to install XML and SAX stuff i killed it. $DEITY knows what
other crap tha module depends on. i would hope zip() doesn't need that
but then why bundle it with stuff that uses so many other modules? bah!

uri
 
D

Dr.Ruud

Uri Guttman schreef:
i was going to skip this but now that you decided it was a good idea,
i have to comment. & has several uses and almost all are poor to bad.
the simplest and safest is that you can call subs without () or
predeclaring them (via use subs or sub foo).

Starting sentences without a capital letter, makes your postings less
readable.
 
D

DJ Stunks

Uri said:
DS> Anno Siegel said:
or, overriding the prototype:

my %character_value = &zip( [ 'a' .. 'z'], [ 1 .. 26]);

DS> :) very nice.

DS> I wasn't totally clear on the role of & previously...

i was going to skip this but now that you decided it was a good idea, i
have to comment. & has several uses and almost all are poor to bad. the
simplest and safest is that you can call subs without () or predeclaring
them (via use subs or sub foo). another thing it does which is very
nasty is to call subs like &foo ;. that passes the currently @_ to the
called sub so this can lead to nasty bugs where you don't deal properly
with @_. the other thing it does is shut off prototypes as anno
shows. but if there was a reason for prototypes (in this case taking two
array args) then defeating that can be nasty. it smacks of breaking
encapsulation as well. i find it troublesome that a prototype of \@
won't allow an array ref to be passed instead of a real array. well p6
will handle that correctly.

Thanks for those explanations.

also i tried to install List::MoreUtils to play with zip but when it
started to install XML and SAX stuff i killed it. $DEITY knows what
other crap tha module depends on. i would hope zip() doesn't need that
but then why bundle it with stuff that uses so many other modules? bah!

Um, I'm not sure what was going on there, but from the README:

List-MoreUtils version 0.18
===========================

<snip>

DEPENDENCIES

This module requires these other modules and libraries:

No modules, but a C compiler would be nice
(although not strictly required)

You might want to try again? it's a very handy module.

-jp
 
U

Uri Guttman

DS> Um, I'm not sure what was going on there, but from the README:

DS> List-MoreUtils version 0.18
DS> ===========================

DS> <snip>

DS> DEPENDENCIES

DS> This module requires these other modules and libraries:

DS> No modules, but a C compiler would be nice
DS> (although not strictly required)

then my cpan.pm is smoking crack. i should probably upgrade it too.

uri
 
R

Rick Scott

(Uri Guttman said:
DS> Anno Siegel said:
or, overriding the prototype:

my %character_value = &zip( [ 'a' .. 'z'], [ 1 .. 26]);

DS> :) very nice.
DS> I wasn't totally clear on the role of & previously...

i was going to skip this but now that you decided it was a good
idea, i have to comment. & has several uses and almost all are
poor to bad. ...
the other thing it does is shut off prototypes as anno shows. but
if there was a reason for prototypes (in this case taking two
array args) then defeating that can be nasty.

Heh. I discovered this when I tried using & to skip zip's prototype:

shadow> cat zip.pl

#!/usr/bin/perl

use warnings;
use strict;
use List::MoreUtils qw(zip);

my %character_value = &zip ('a'..'z', 1..26);

shadow> ./zip.pl
Segmentation fault

Can't say I've ever managed to do that with Perl before.




Rick
 
A

Anno Siegel

Rick Scott said:
(Uri Guttman said:
"DS" == DJ Stunks <[email protected]> writes:

DS> Anno Siegel said:
or, overriding the prototype:

my %character_value = &zip( [ 'a' .. 'z'], [ 1 .. 26]);

DS> :) very nice.
DS> I wasn't totally clear on the role of & previously...

i was going to skip this but now that you decided it was a good
idea, i have to comment. & has several uses and almost all are
poor to bad. ...
the other thing it does is shut off prototypes as anno shows. but
if there was a reason for prototypes (in this case taking two
array args) then defeating that can be nasty.

Heh. I discovered this when I tried using & to skip zip's prototype:

shadow> cat zip.pl

#!/usr/bin/perl

use warnings;
use strict;
use List::MoreUtils qw(zip);

my %character_value = &zip ('a'..'z', 1..26);

shadow> ./zip.pl
Segmentation fault

Can't say I've ever managed to do that with Perl before.

Ah, it looks like zip() believes in its prototype and doesn't check
its arguments. It's easy to segfault that way.

Anno
 
T

Tassilo v. Parseval

Also sprach Uri Guttman:
DS> Anno Siegel said:
or, overriding the prototype:

my %character_value = &zip( [ 'a' .. 'z'], [ 1 .. 26]);

DS> :) very nice.

DS> I wasn't totally clear on the role of & previously...
[...]

also i tried to install List::MoreUtils to play with zip but when it
started to install XML and SAX stuff i killed it. $DEITY knows what
other crap tha module depends on. i would hope zip() doesn't need that
but then why bundle it with stuff that uses so many other modules? bah!

'scuse me? List::MoreUtils has no dependencies whatsoever:

WriteMakefile(
NAME => 'List::MoreUtils',
VERSION_FROM => 'lib/List/MoreUtils.pm',
PREREQ_PM => {},
($] >= 5.005 ?
(ABSTRACT_FROM => 'lib/List/MoreUtils.pm',
AUTHOR => 'Tassilo von Parseval <[email protected]>') : ()),
DEFINE => '-DPERL_EXT', # otherwise 'cxinc' isn't defined
CONFIGURE => \&init,
clean => { FILES => 'test.c' }
);

and I took great effort that both the XS- and the Perl-implementation of
its functions work on anything between 5.005_04 and 5.9.4.

Check your CPAN setup. It's borked. :)

Tassilo
 

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

Forum statistics

Threads
473,744
Messages
2,569,482
Members
44,900
Latest member
Nell636132

Latest Threads

Top