Why are some hashes initialized using curly braces, and some with parentheses? - perl

I'm looking at the following code demonstrating nested hashes:
my %HoH = (
flintstones => {
husband => "fred",
pal => "barney",
},
jetsons => {
husband => "george",
wife => "jane",
"his boy" => "elroy", # Key quotes needed.
},
simpsons => {
husband => "homer",
wife => "marge",
kid => "bart",
},
);
Why is it that the upper-most hash (starting line 1) is initialized using parentheses, whereas the sub-hashes are initialized using curly braces?
Coming from a python background I must say Perl is quite odd :).

Coming from a Perl background I find Perl quite odd, too.
Use parentheses to initialize a hash (or an array). A hash is a map between a set of strings and a set of scalar values.
%foo = ( "key1", "value1", "key2", "value2", ... ); # % means hash
%foo = ( key1 => "value1", key2 => "value2", ... ); # same thing
Braces are used to define a hash reference. All references are scalar values.
$foo = { key1 => "value1", key2 => "value2", ... }; # $ means scalar
Hashes are not scalar values. Since the values in a hash must be scalars, it is therefore not possible to use a hash as a value of another hash.
%bar = ( key3 => %foo ); # doesn't mean what you think it means
But we can use hash references as values of another hash, because hash references are scalars.
$foo = { key1 => "value1", key2 => "value2" };
%bar = ( key3 => $foo );
%baz = ( key4 => { key5 => "value5", key6 => "value6" } );
And that is why you see parentheses surrounding a list of lists with braces.

The essential difference (....) is used to create a hash. {....} is used to create a hash reference
my %hash = ( a => 1 , b => 2 ) ;
my $hash_ref = { a => 1 , b => 2 } ;
In a bit more detail - {....} makes an anonymous hash and returns a reference to it wich is asigned to the scalar $hash_ref
edited to give a bit more detail

First, the parens do nothing but change precedence here. They never have nothing to do with list creation, hash creation or hash initialisation.
For example, the following two lines are 100% equivalent:
{ a => 1, b => 2 }
{ ( a => 1, b => 2 ) }
For example, the following two lines are 100% equivalent:
sub f { return ( a => 1, b => 2 ) } my %hash = f();
sub f { return a => 1, b => 2 } my %hash = f();
Second, one doesn't initialise a hash using { }; one creates a hash using it. { } is equivalent to my %hash;, except that the hash is anonymous. In other words,
{ LIST }
is basically the same as
do { my %anon = LIST; \%anon }
(but doesn't create a lexical scope).
Anonymous hashes allows one to write
my %HoH = (
flintstones => {
husband => "fred",
pal => "barney",
},
jetsons => {
husband => "george",
wife => "jane",
"his boy" => "elroy",
},
simpsons => {
husband => "homer",
wife => "marge",
kid => "bart",
},
);
instead of
my %flintstones = (
husband => "fred",
pal => "barney",
);
my %jetsons = (
husband => "george",
wife => "jane",
"his boy" => "elroy",
);
my %simpsons = (
husband => "homer",
wife => "marge",
kid => "bart",
);
my %HoH = (
flintstones => \%flinstones,
jetsons => \%jetsons,
simpsons => \%simpsons,
);

Related

Moose empty value for typed attributes

Is there some way in Moose to specify that I want an attribute to have a specific type, but also allow there to be a null value (undef?).
For example I am writing a simple implementation of a Linked List and have a Node class where the next and prev pointers are required to be of type Node (this is probably what you would expect)
package Node;
{
use Moose;
has 'value' => (
is => 'rw',
isa => 'Any', # Nodes can be of any type
);
has 'prev' => (
is => 'rw',
isa => 'Node',
predicate => 'has_prev',
);
has 'next' => (
is => 'rw',
isa => 'Node',
predicate => 'has_next',
);
}
But I was hoping to use a sentinel, empty node stored at the head of the list to mark the head, instead of an actual element of the list. So a list of elements [1, 2, 3] would actually look like:
EMPTY -> 1 -> 2 -> 3
I was hoping to be able to specify a empty value (like undef) for the next and prev pointers, but when I create an empty Node in my List class:
package List;
{
use Moose;
has 'head' => (
is => 'rw',
isa => 'Node',
# empty head node
default => sub {
Node->new( value => undef, next => undef, prev => undef );
},
);
Moose complains because undef is not of type Node.
Is there a way around this ?
You can use the Maybe[type] syntax to allow the type or undef. For your example:
has 'head' => (
is => 'rw',
isa => 'Maybe[Node]',
# empty head node
default => sub {
Node->new( value => undef, next => undef, prev => undef );
}
);
The next:
use 5.014;
use warnings;
package Node {
use Moose;
has 'value' => ( is => 'rw');
has 'prev' => ( is => 'rw', isa => 'Undef|Node', predicate => 'has_prev', default=>undef );
has 'next' => ( is => 'rw', isa => 'Undef|Node', predicate => 'has_next', default=>undef );
}
package List {
use Moose;
has 'head' => ( is => 'rw', isa => 'Node', default => sub { Node->new() } );
}
package main;
use Data::Dumper;
my $list = List->new();
say Dumper $list;
prints:
$VAR1 = bless( {
'head' => bless( {
'next' => undef,
'prev' => undef
}, 'Node' )
}, 'List' );
The Moose::Manual::Types says for the basic hier:
Undef <---- undefined
Defined
Value
Str
Num
Int
ClassName <---- Class name
RoleName
and later in the section TYPE UNIONS says:
Moose allows you to say that an attribute can be of two or more
disparate types. For example, we might allow an Object or FileHandle:
has 'output' => (
is => 'rw',
isa => 'Object | FileHandle', );
As others already says, here is a Maybe[Something] too, I haven't idea what is better, but the Something | SomethingOther looks more "perlish" (IMHO). ;)
The authors prefer Undef|Node over Maybe[Node].
has 'prev' => (
is => 'rw',
isa => 'Undef|Node',
predicate => 'has_prev',
);

Compare and edit underlying structure in hash

I have a hash of complex structure and I want to perform a search and replace. The first hash is like the following:
$VAR1 = {
abc => { 123 => ["xx", "yy", "zy"], 456 => ["ab", "cd", "ef"] },
def => { 659 => ["wx", "yg", "kl"], 456 => ["as", "sd", "df"] },
mno => { 987 => ["lk", "dm", "sd"] },
}
and I want to iteratively search for all '123'/'456' elements, and if a match is found, I need to do a comparison of the sublayer, i.e. of ['ab','cd','ef'] and ['as','sd','df'] and in this case, keep only the one with ['ab','cd','ef']. So the output will be as follows:
$VAR1 = {
abc => { 123 => ["xx", "yy", "zy"], 456 => ["ab", "cd", "ef"] },
def => { 659 => ["wx", "yg", "kl"] },
mno => { 987 => ["lk", "dm", "sd"] },
}
So the deletion is based on the substructure, and not index. How can it be done? Thanks for the help!!
Lets assume that I will declare the values to be kept, i.e. I will keep 456 => ["ab", "cd", "ef"] based on a pre-declared value of ["ab", "cd", "ef"] and delete any other instance of 456 anywhere else. The search has to be for every key. so the code will go through the hash, first taking 123 => ["xx", "yy", "zy"] and compare it against the keys throughout the rest of the hash, if no match is found, do nothing. If a match is found, like in the case of 456 => ["ab", "cd", "ef"], it will compare the two, and as I have said that in case of a match the one with ["ab", "cd", "ef"] would be kept, it will keep 456 => ["ab", "cd", "ef"] and discard any other instances of 456 anywhere else in the hash, i.e. it will delete 456 => ["as", "sd", "df"] in this case.
Here is a solution that uses the smart match operator to perform the array comparison:
Update: as Borodin pointed out, my original code was wrong. This is the fixed version.
Update 2: Changed it to choose the values to keep based on a hash structure.
my $VAR1 = {
abc => { 123 => ["xx", "yy", "zy"], 456 => ["ab", "cd", "ef"] },
def => { 659 => ["wx", "yg", "kl"], 456 => ["as", "sd", "df"] },
mno => { 987 => ["lk", "dm", "sd"] },
};
my %keep_values = (
'456' => ['ab','cd','ef']
);
foreach my $outer_key (keys %$VAR1)
{
foreach my $keepers (keys %keep_values)
{
if (exists $VAR1->{$outer_key}{$keepers} and
#use the smart match operator to compare arrays.
!(#{$VAR1->{$outer_key}{$keepers}} ~~ #{$keep_values{$keepers}}))
{
delete $VAR1->{$outer_key}{$keepers};
}
}
}
For more on the smart match operator, see perlop.

Perl hash negation

Can you help me correct the code snippet.
I want to list the server which is type eq xyz but not with namedservers.
our %SERVERS = (
"rajesh1" => {type => 'xyz', sha => 'ram'},
"rajesh2" => {type => 'xyz', sha => 'sita'},
"rajesh3" => {type => 'xyz', named => ["raa"]},
"rajesh4" => {type => 'xxx', named => ["rajjaj"]},
);
while ( my $mServer = each(%SERVERS) )
{
if ("$SERVERS{$mServer}{type}" eq "xyz" && !"$SERVERS{$mServer}{named}" )
{
print "Name of the server is $mServer\n";
}
}
Expected result:
rajesh1
rajesh2
You're missing a semicolon after the definition of %SERVERS.
You start calling it $mServer, then later say $gServer. Pick one!
Get rid of the quotes around $SERVERS{$mServer}{type} and $SERVERS{$mServer}{named} (once you've changed gServer to mServer—you don't need them.
You expect to see "rajesh1 rajesh2", but none of them have type "prod". How is that possible? Assuming you change their type to "prod" …
You expect to see "rajesh1 rajesh2", but you print "Name of the server is $mServer\n" (once you change gServer to mServer). Changing that to just "$mServer\n", and …
… it should work.
Hence:
our %SERVERS = (
"rajesh1" => {type => 'prod', sha => 'ram'},
"rajesh2" => {type => 'prod', sha => 'sita'},
"rajesh3" => {type => 'xyz', named => ["raa"]},
"rajesh4" => {type => 'xxx', named => ["rajjaj"]},
);
while (my $mServer = each %SERVERS) {
if ($SERVERS{$mServer}{type} eq "prod" && !$SERVERS{$mServer}{named}) {
print "$mServer\n";
}
}
Then:
$ perl test.pl
rajesh1
rajesh2
$
Complete sample, catching both of each's return values, which reduces visual clutter:
use strict;
use warnings;
our %SERVERS = (
"rajesh1" => {type => 'xyz', sha => 'ram'},
"rajesh2" => {type => 'xyz', sha => 'sita'},
"rajesh3" => {type => 'xyz', named => ["raa"]},
"rajesh4" => {type => 'xxx', named => ["rajjaj"]},
"rajesh5" => {type => 'prod', sha => 'ram'},
"rajesh6" => {type => 'prod', named => ["jajaja"]},
);
while ( my( $mServer, $mData ) = each %SERVERS ) {
if ($mData->{type} eq "prod" && !$mData->{named}) {
print "Name of the server is $mServer\n";
}
}
You are looking for defined.
if ($SERVERS{$mServer}->{type} eq "xyz" &&
! defined $SERVERS{$mServer}->{named} )
...
You were using an undefined variable $gServer where apparently you meant to use the loop variable $mServer. You should use strict; use warnings; in all your scripts; that makes it easy to catch this mistake (and a slew of others).
I use the indirection operator -> to access the contents of hash references as a matter of preference. I also removed some gratuitous quoting as a stylistic change.

Lazy Attribute Coercion

With Moose, you can have lazy builders on attributes, where the builder is called when the attribute is first accessed if the attribute was not already populated. You can have type coercion of an attribute with coerce, but this is applied whenever the attribute is set, so even on object initialization.
I'm looking for a way to implement lazy coercion, where an attribute may be initially populated, but is only coerced when it is first accessed. This is important when coercion is expensive.
In the following example, I use a union type and method modifiers to do this:
package My::Foo;
use Moose;
has x => (
is => 'rw',
isa => 'ArrayRef | Int',
required => 1
);
around "x" => sub {
my $orig = shift;
my $self = shift;
my $val = $self->$orig(#_);
unless(ref($val)) {
# Do the cocerion
$val = [ map { 1 } 1..$val ];
sleep(1); # in my case this is expensive
}
return $val;
};
1;
my $foo = My::Foo->new( x => 4 );
is_deeply $foo->x, [ 1, 1, 1, 1 ], "x converted from int to array at call time";
However there are a few problems with this:
I dislike the union type + method modifier approach. It goes against the "Best Practices" suggestion to use coercion instead of unions. It isn't declarative.
I need to do this with many attributes across many classes. Therefore some form of DRY is needed. This could be meta-attribute roles, type-coercion, what have you.
Update:
I followed ikegami's suggestion to encapsulate the expensive type coercion inside an object and provide an outer coercion to this object:
package My::ArrayFromInt;
use Moose;
use Moose::Util::TypeConstraints;
subtype 'My::ArrayFromInt::Inner',
as 'ArrayRef[Int]';
coerce 'My::ArrayFromInt::Inner',
from 'Int',
via { return [ (1) x $_ ] };
has uncoerced => (is => 'rw', isa => 'Any', required => 1);
has value => (
is => 'rw',
isa => 'My::ArrayFromInt::Inner',
builder => '_buildValue',
lazy => 1,
coerce => 1
);
sub _buildValue {
my ($self) = #_;
return $self->uncoerced;
}
1;
package My::Foo;
use Moose;
use Moose::Util::TypeConstraints;
subtype 'My::ArrayFromInt::Lazy' => as class_type('My::ArrayFromInt');
coerce 'My::ArrayFromInt::Lazy',
from 'Int',
via { My::ArrayFromInt->new( uncoerced => $_ ) };
has x => (
is => 'rw',
isa => 'My::ArrayFromInt::Lazy',
required => 1,
coerce => 1
);
1;
This works if $foo->x->value is called. However this doesn't solve point #2, as I would need to create My::ArrayFromInt and the ::Lazy subtype for each attribute I would like to transform. And I'd like to avoid calling $foo->x->value if possible.
How about having the typedef along the lines described, then doing
has _x => (
is => 'ro',
isa => 'Int|MyArrayOfInts',
init_arg => 'x',
required => 1,
);
has x => (
is => 'ro',
lazy => 1,
isa => 'MyArrayOfInts',
coerce => 1,
default => sub { $_[0]->_x },
);
It'd make sense to wrap that up into some kind of helper method to create the pair of objects along the lines of
has_lazily_coerced x => (
is => 'ro',
isa => 'TargetType',
);
which would introspect on TargetType to get a list of legal types for the uncoerced shadow attribute and generate the pair of attributes for you.

How do I sort by value from a second level hash, in Perl?

my $hash_ref = {
one => { val => 1, name => 'one' },
three => { val => 3, name => 'three'},
two => { val => 2, name => 'two' },
};
I would like to sort $hash_ref such that a foreach would order them by
$hash_ref->{$key}->{'val'}
one
two
three
Any suggestions?
#sorted_list is an array of references to the sorted hash elements:
#sorted_list = sort { $a->{'val'} <=> $b->{'val'} } values %{$unsorted_hash_ref};
You can use it like so:
#!/usr/bin/perl
my $hash_ref = {
one => { val => 1, name => 'one' },
three => { val => 3, name => 'three' },
two => { val => 2, name => 'two' },
};
foreach $elem ( sort { $a->{'val'} <=> $b->{'val'} } values %{$hash_ref} ) {
print "$elem->{'val'} : $elem->{'name'}\n";
}
Output:
1 : one
2 : two
3 : three
Hash tables don't have any specific order. However, you can sort the keys in an array and use that to iterate through the hash:
my $hash_ref = {
one => { val => 1, name => 'one'},
three => { val => 3, name => 'three'},
two => { val => 2, name => 'two'},
};
use strict;
use warnings;
use Lingua::EN::Words2Nums;
foreach my $key (sort { words2nums($a) <=> words2nums($b) } keys %$hash_ref)
{
# do something with $hash_ref->{$key}
print "processing key $key.\n";
}
You can define anything you like as a sort method; see perldoc -f sort for more details. Conversion from ordinal numerical text to arithmetic values is done with Lingua::EN::Words2Nums (it does cardinal numbers too).
use strict;
use warnings;
my %hash_ref = (
one => { val => 1, name => 'one' },
three => { val => 3, name => 'three'},
two => { val => 2, name => 'two' },
);
foreach my $key(sort {$hash_ref{$a}{val} <=> $hash_ref{$b}{val}} keys %hash_ref) {
my $value = $hash_ref{$key}{val};
my $name = $hash_ref{$key}{name};
print "$name -> $value\n";
}
output:
one -> 1
two -> 2
three -> 3
#!/usr/bin/perl
my $hash_ref = (
one => {val => 1, name => "one"},
three => {val => 3, name => "three"},
two => {val => 2, name => 'two'},
);
foreach $elem( sort {$$hash_ref{$a}{val} <=> $$hash_ref{$b}{val}} keys %$hash_ref){
my $value = $hash_ref->{$elem}{val};
my $name = $hash_ref->{$elem}{name};
print "$name -> $value\n";
}
OutPut:
one -> 1
two -> 2
three -> 3