Trouble passing hash and variable to subroutine - perl

I want to pass a hash and a variable to a subroutine:
%HoA = {'1'=>'2'};
my $group_size = 10;
&delete_unwanted(\%HoA,$group_size);
sub delete_unwanted {
my (%HoA,$group_size) = #_;
print "'$group_size'\n"
}
But, this prints nothing.

You're passing a hash reference (as you should), so therefore assign it to a scalar in your parameter catching:
sub delete_unwanted {
my ($hashref, $group_size) = #_;
print "'$group_size'\n"
}
If you later want to dereference it, you can my %newHoA = %$hashref;, but that will be a copy of the original hash. To access the original structure, just use the reference: print $hashref->{a_key};.

Your problem is in:
my (%HoA,$group_size) = #_;
You can solve it by saying, for example:
sub delete_unwanted {
my $hashPointer = shift;
my $group_size = shift
Note that you can retrieve the original hash inside the subroutine by either: de-referencing the hashPointer (my %HoA = %$hashPointer), or you can access the hash contents directly using the pointer directly (eg, $hashPointer->{'key'})

Related

Perl copy scalar to a hash

I have a hash which I am passing to a subroutine. I pass an empty hash to subroutine as well. I want to copy the contents of the hash to the empty one.
Here's how my code looks:
my %emptyHash = ();
my %sourceHash = ();
$sourceHash{'apple'} = 'red';
$sourceHash{'orange'} = 'orange';
mergeHash(\%emptyHash, \%sourceHash);
foreach my $k (keys %emptyHash)
{
print "key=>". $k. "value=>".$emptyHash{$k}. "\n";
}
sub mergeHash {
my $emptyHash = shift;
my $sourceHash = shift;
$emptyHash = $sourceHash;
}
When I print the emptyHash after the merge, I still get an empty hash. Can I not just copy the value of one hash to another this way?
$emptyhash and $sourcehash are references. When you do $emptyhash = $sourcehash you just make the variable $emptyhash contain the same reference that $sourcehash does.
Instead, you want %$emptyhash = %$sourcehash, which acts on the hashes those references point to.
Do you want a quick copy or a deep one? A quick copy copies only the top-level scalars of a hash. If the hash contains anonymous arrays or hashes, they will not be copied. Instead, a reference to them is made. That means any changes inside of them will cause the same changes in the copied hash.
Quick copy:
%$empty_hash = %$source_hash;
Deep copy:
use Storable qw( dclone );
$empty_hash = declone( $source_hash );
Storable is a standard module that comes with Perl. For a list of the standard modules, see perldoc perlmodlib.
I fixed your code below.
my %emptyHash = ();
my %sourceHash = ();
$sourceHash{'apple'} = 'red';
$sourceHash{'orange'} = 'orange';
my $d = mergeHash(\%emptyHash, \%sourceHash);
foreach my $k (keys %$d)
{
print "key=>". $k. "\tvalue=>". $emptyHash{$k}. "\n";
}
sub mergeHash {
my $emptyHash = shift;
my $sourceHash = shift;
%$emptyHash = %$sourceHash;
return $emptyHash;
}

How to access hash from object

I have written a small class which just got some getter and setter methods. One of those Properties is a hash.
sub getMyData
{
my $objekt = shift;
return $objekt->{MYDATA};
}
sub setMyData
{
my $objekt = shift;
my %myData= shift;
$objekt->{MYDATA} = \%myData;
}
If i set the value like this in another skript which access my class:
my %test;
$test{'apple'}='red';
$objekt = MYNAMESPACE::MYCLASS->new;
$objekt->setMyData(%test);
I thought i can access this value easy via:
my $data = $objekt->getMyData;
print $data{'apple'};
I just get undef value.
Output from Dumper:
Can someone tell me what's wrong here and how i can access getMyData and print the value 'red'?
shift removes and returns the first element of an array. Inside of a subroutine a bare shift operates on #_, which contains a copy of all arguments passed to that subroutine.
What is really happening here is that setMyData is being passed this data:
setMyData($objekt, 'apple', 'red');
The first shift in setMyData removes $objekt from #_
The second shift in setMyData removes 'apple', but since you assign the result of this shift to a Hash it creates a Hash that looks like this: 'apple' => undef
You take a reference to this Hash and store it in the MYDATA key of $objekt
What you really want is to assign the remainder of #_ to your Hash:
sub setMyData {
my $objekt = shift;
my %myData = #_;
# my ($objekt, %myData) = #_; (alternative)
$objekt->{MYDATA} = \%myData;
}
Another option is to instead send a Hash reference to setMyData, which would work with shift:
sub setMyData {
my $objekt = shift;
my $myData_ref = shift
$objekt->{MYDATA} = $myData_ref;
}
$objekt->setMyData(\%test);
You are missing the dereference arrow. Because you put a hashref (\%myData) in, you also get a reference out.
my $data = $objekt->getMyData;
print $data->{'apple'};
# ^
# here
You also need to change the assignment, because you are passing a list to the setter, not a reference. shift is for scalar (single) values, but %test gets turned into a list (many values).
sub setMyData
{
my $objekt = shift;
my %myData = #_;
$objekt->{MYDATA} = \%myData;
}
However, there are a few more issues with your code.

Filling hash by reference in a procedure

I'm trying to call a procedure, which is filling a hash by reference. The reference to the hash is given as a parameter. The procedure fills the hash, but when I return, the hash is empty. Please see the code below.
What is wrong?
$hash_ref;
genHash ($hash_ref);
#hash is empty
sub genHash {
my ($hash_ref)=(#_);
#cut details; filling hash in a loop like this:
$hash_ref->{$lid} = $sid;
#hash is generetad , filled and i can dump it
}
You might want to initialize hashref first,
my $hash_ref = {};
as autovivification happens inside function to another lexical variable.
(Not so good) alternative is to use scalars inside #_ array which are directly aliased to original variables,
$_[0]{$lid} = $sid;
And btw, consider use strict; use warnings; to all your scripts.
The caller's $hash_ref is undefined. The $hash_ref in the sub is therefore undefined too. $hash_ref->{$lid} = $sid; autovivifies the sub's $hash_ref, but nothing assigns that hash reference to the caller's $hash_ref.
Solution 1: Actually passing in a hash ref to assign to the caller's $hash_ref.
sub genHash {
my ($hash_ref) = #_;
...
}
my $hash_ref = {};
genHash($hash_ref);
Solution 2: Taking advantage of the fact that Perl passes by reference.
sub genHash {
my $hash_ref = $_[0] ||= {};
...
}
my $hash_ref;
genHash($hash_ref);
-or-
genHash(my $hash_ref);
Solution 3: If the hash is going to be empty initially, why not just create it in the sub?
sub genHash {
my %hash;
...
return \%hash;
}
my $hash_ref = genHash();

Passing variables through functions

When I pass a variable through a couple of subs, it always turns up empty. Why is this ?
sub Main {
my $myVariable = "Test string";
firstSub($myVariable);
}
sub firstSub {
my($myVariable) = #_;
my #array = `some command`;
secondSub(#array, $myVariable);
}
sub secondSub {
my(#array, $myVariable) = #_;
print $myVariable;
}
echo will be undef.
echo is not a valid Perl function. You're confusing shells with Perl here. Try "print" or "say" (the latter with Perl 5.10 and newer).
Also you cannot assign an array & a scalar variable to another array & scalar variable. Meaning this won't work because all of the elements of the right-hand side will be assigned to the array on left-hand side, and nothing will be assigned to the scalar: my (#array, $myVariable) = #_; Either swap the order of the elements my ($myVariable, #array) = #_; (also when calling the function) or use array references instead of full arrays.
Your code doesn't do anything because you have defined three subroutines, but you have never called them.
Just add Main(); to actually run your main sub.
Also, you need print instead of echo.
Also, the passing of variables is incorrect, as Moritz Bunkus explained.
When you call secondsub() the #array and the $myVariable is being sent as a list(a single element) and is been assigned to #array in the secondsub function. You can see both the #array and $myVariable values when you print #array in secondsub.
You have to pass the array as a reference and receive it as a scalar value in secondsub. The below code will work.
&Main();
sub Main {
my $myVariable = "Test string";
firstSub($myVariable);
}
sub firstSub {
my($myVariable) = #_;
my #array = `some command`;
secondSub(\#array,$myVariable);
}
sub secondSub {
my($ref,$myVariable) = #_;
print $myVariable;
}
Passing varibles:
my $txt = "this text for sample";
Function_Passing_varible($txt);
sub Function_Passing_varible{
my $text = shift;
print $text;
}
I think you like this answer......

Perl woes - assigning and returning a hashes

I have an instance variable, properties, that is being declared and instantiated like so:
$self->{properties}{$key1} = $value;
My understanding that this will declare the properties field, and also set it to a Hash primitive, containing one key value pair.
I'm trying to write a getter for the properties instance variable, that will return the hash:
sub getProperties{
my $self = shift;
my %myhash = $self->{properties};
return %myhash;
}
And subsequently call the getter like so:
my %properties = $properties->getProperties();
When I try to compile this i get:
"Odd number of elements in hash assignment at 70..."
line 70 being: my %myhash = $self->{properties};
In this line of code:
my %myhash = $self->{properties};
%myhash is a hash whereas $self->{properties} is a hash reference. So you're effectively returning a hash with one key/value pair where the key is a reference to a hash and the value is undef.
If you really want to return a hash, do this:
my %myhash = %{$self->{properties}};
Alternatively, return a hash reference. That's generally preferable to returning a hash, since it doesn't make a copy of the original hash and therefore is more memory efficient as the hash gets larger. Here's how it looks:
sub getProperties {
my $self = shift;
return $self->{properties};
}
Then in your calling code instead of this:
my %properties = $properties->getProperties();
$somevalue = $properties{'somekey'};
do this:
# getProperties returns a reference, so assign to a scalar
# variable ($foo) rather than a hash (%foo)
my $properties = $properties->getProperties();
# Use -> notation to dereference the hash reference
$somevalue = $properties->{'somekey'};
isn't $self->{properties} a hashref not a hash?
$ perl t4.pl
size -> 42
t4.pl
#!/usr/bin.perl
use strict;
use warnings;
use t4;
my $t4 = t4->new();
my %hash = $t4->getProperties();
for my $key (keys %hash) {
print "$key -> $hash{$key}\n";
}
t4.pm
package t4;
sub new {
my $class = shift;
my $self = {};
$self->{properties}{size} = 42;
bless ($self, $class);
}
sub getProperties {
my $self = shift;
my %myhash = %{$self->{properties}};
return %myhash;
}
1;