I can't print keys and values in Perl - perl

I have a data structure that I got from this code.
my $name = $data->{Instances}->[0]->{Tags};
That data structure looks like this
$VAR1 = [
{
'Key' => 'Name',
'Value' => 'fl-demo'
},
{
'Value' => 'FL',
'Key' => 'state'
}
];
I'm trying to print the keys and values with this
foreach my $key (sort keys %$name) {
my $value = $name->{$key};
print "$key => $value\n";
}
I'm getting
Not a HASH reference at ./x.pl line 19.

The tags are returned as an array, not a hash. So you're looking at doing something like this, instead, to iterate over them:
foreach my $tag (#$name) {
my $key = $tag->{Key};
my $val = $tag->{Value};
print "$key => $val\n";
}

The data structure dump of variable $name indicates that you have array reference.
You can use loop to output the data of interest, do not forget to dereference $name variable.
use strict;
use warnings;
use feature 'say';
my $name = [
{
'Key' => 'Name',
'Value' => 'fl-demo'
},
{
'Value' => 'FL',
'Key' => 'state'
}
];
say "$_->{Key} = $_->{Value}" for #$name;
Output
Name = fl-demo
state = FL

Elaborating on a previous answer:
$name is a reference to an array containing references to hashes.
#$name and #{$name} (equivalent representations) refer to the array that $name references.
${$name}[0] and $name->[0] (equivalent representations) refer to the first hash in the array referenced by $name.
${$name}[0]{'Key'}, $name->[0]->{'Key'}, etc. (equivalent representations) refer to 'Key''s hash value in the first hash in the array referenced by $name.
As such, the following would iterate over all array and hash elements:
foreach my $hashref ( #{$name} )
{
foreach my $key ( sort(keys(%{$hashref})) )
{
printf("%s => %s\n",$key,$hashref->{$key});
}
print "\n";
}
Or, more compactly (and arguably unreadably):
printf("%s\n",join("\n", map {
my $h = $_;
join(', ', map { sprintf('%s=%s',$_,$h->{$_}) } sort(keys(%{$h})) );
} #{$name} ));

Related

Working with structures and hashes in Perl

Consider the following structure in Perl: (let's call it declaration A)
my $json_struct = {
name => $name,
time => $time,
};
I have a hash %hash which contains custom fields (I don't know how many). It looks something like this:
$VAR1 = {
'key2' => '123',
'key1' => 'abc',
'key3' => 'xwz'
};
I would like to loop through the hash keys and insert those keys into the structure, so I thought that I can do something like this:
foreach my $key (keys %hash) {
push #{ $json_struct }, { $key => $hash{$key} };
}
I'm not sure that it is working as expected. Also, is there a cleaner way to do so? Maybe I can combine it in one or two lines while declaring A.?
Expected output: (order does not matter)
$VAR1 = {
'name' => $name,
'time' => $time,
'key2' => '123',
'key1' => 'abc',
'key3' => 'xwz'
};
$json_struct is a hash reference, but #{ $json_struct } performs array dereferencing on $json_struct, so that is not going to work.
There is no push operator for hashes; you just insert new data by assigning values to new keys. For your structure, you would just want to say
foreach my $key (keys %hash) {
$json_struct->{$key} = $hash{$key};
}
Now you can also use the #{...} operator to specify a hash slice, which may be what you were thinking of. Hash slices can be used to operate on several keys of a hash simultaneously. The syntax that will work for you for that operation is
#{$json_struct}{keys %hash} = values %hash;
The easiest way to join hashes is like this:
my $foo = {
name => $name,
time => $time,
};
my $bar = {
'key2' => '123',
'key1' => 'abc',
'key3' => 'xwz'
};
my $combined = {
%{$foo},
%{$bar},
};

Iterate through values of a HASH and convert to comma separated strings

I want to iterate through the values of a big hash, and if any of the values of that hash are keys, I want to convert it into a comma separated list which can be parsed in 'query_form'.
Right now from the data below I have:
name=Bob&surname=Whitbread&customerErrors=HASH(Xa456) (for example)
Here's what I have so far:
sub convertArgsToQueryString {
my $class = shift;
my $args = shift;
return unless ($args && ref($args) eq 'HASH');
foreach my $key (values %$args) {
if (ref($key) eq 'HASH') {
# change to a comma separated list
}
}
my $dummyURL = URI->new('', 'http');
$dummyURL->query_form(%$args);
return $dummyURL->query;
}
Data:
my $data = {
'name' => 'Bob',
'surname' => 'Whitbread',
'customerErrors' => {
'error1' => 'paymentError',
'error2' => 'addressError'
},
};
Query Form:
name=Bob&surname=Whitbread&customerErrors=paymentError,addressError
This will do what you want
print join ",", values %{$data->{customerErrors}},"\n";
Although I would suggest, rather than error1 as hash keys, you'd be better off with an array:
my $data = {
'name' => 'Bob',
'surname' => 'Whitbread',
'customerErrors' => [ 'paymentError', 'addressError' ],
};
Scaling that out to be generic, you will find the ref function to be helpful:
foreach my $key ( keys %$data ) {
print "$key is a ", ref $data->{$key},"\n";
if ( ref $data->{$key} eq 'HASH' ) {
print join ",", values %{$data->{$key}};
}
else {
print $data -> {$key},"\n";
}
}
Or tersely:
print join "\&", map { #join iterated on &
join "=", $_, #join paired values on =
ref $data->{$_} eq 'HASH' #ternary to check reference type
? values %{ $data->{$_} } #extract values if HASH
: $data->{$_} #extract just value if not.
} keys %$data; #iterate keys of data
Which gives as output:
name=Bob&customerErrors=addressError=paymentError&surname=Whitbread

Perl get value of a key

I have been stuck in trying to create an array of keys (example_com,example_ca ..etc) if they are set to 1, I have tried using for loop and foreach loop, but keep getting ARRAY# error.
$VAR1 = [
{
'example_com' => '1',
'example_ca' => '1'
}
];
Thanks
This will be because you have an array containing a hash. The array is one element long.
So you 'get' to the hash, by dereferencing element zero.
Thus:
my $hash_ref = $VAR1->[0];
print join "\n", keys %{$hash_ref},"\n";
foreach my $key ( keys %{$VAR1->[0]} ) {
print "$key => $VAR1->[0]{$key}\n";
}
Exactly for you source data:
my #array_of_keys = ();
for( keys %{ $VAR1->[0] } ) {
push #array_of_keys, $_ if $VAR1->[0]{ $_ } eq '1';
}
print "Keys with 1: #array_of_keys";
An expanded example of how to get an array of keys if you have multiple hashes in your container array:
my $VAR1 = [
{
'example_com' => '1',
'example_ca' => '1',
'not_set' => '0'
},
{
'EXAMPLE_com' => '1',
'EXAMPLE_ca' => '1',
'NOT_SET' => '0',
}
];
my #arrayOfHashes = #{$VAR1};
foreach my $array (#arrayOfHashes)
{
my #onlyOnes;
my #arrayOfKeys = sort keys %{$array};
foreach my $key (#arrayOfKeys)
{
next if ($array->{$key} ne 1);
push #onlyOnes, $key;
}
print "\nKey names:\n";
foreach my $key (#onlyOnes)
{
print "$key\n";
}
}
output:
Key names:
example_ca
example_com
Key names:
EXAMPLE_ca
EXAMPLE_com

Accessing fields of structs in array

I have an array of structs (from Class::Struct) and I am having trouble accessing their 'fields'. I've looked at other solutions such as Perl - Class::Struct Deferencing array and Perl documentation without success. My code is:
use Class::Struct;
use Data::Dump qw(dump);
struct( Tag => {
attributes => '%',
value => '$'
});
my #data = [];
push #data, Tag->new(attributes => { 'id' => 1 }, value => "hello world!");
dump #data;
my $tag = $data[0];
my $value = $tag->value;
print $value, "\n";
I've tried variations on blessing $tag with 'Tag' (since can't call value on unblessed ... is the current error), dereferencing $tag as a hash, and more.
Your error is in initialization of #data:
my #data = []; # the same as my #data = ( [] );
You declare array called #data and initialize it with one empy array ref.
Next you push second element to array using push. Your class now in $data[1].
So fixed example:
struct( Tag => {
attributes => '%',
value => '$'
});
my #data;
push #data, Tag->new(attributes => { 'id' => 1 }, value => "hello world!");
my $tag = $data[0];
my $value = $tag->value;
print $value, "\n";

Perl accessing the elements in a hash/hash reference data structure

I have a question I'm hoping you could help with as I am new to hashes and hash reference stuff?
I have the following data structure:
$VAR1 = {
'http://www.superuser.com/' => {
'difference' => {
'http://www.superuser.com/questions' => '10735',
'http://www.superuser.com/faq' => '13095'
},
'equal' => {
'http://www.superuser.com/ ' => '20892'
}
},
'http://www.stackoverflow.com/' => {
'difference' => {
'http://www.stackoverflow.com/faq' => '13015',
'http://www.stackoverflow.com/questions' => '10506'
},
'equal' => {
'http://www.stackoverflow.com/ ' => '33362'
}
}
If I want to access all the URLs in the key 'difference' so I can then perform some other actions on the URLs, what is the correct or preferred method of accessing those elements?
e.g I will end up with the following URLs that I can then do stuff to in a foreach loop with:
http://www.superuser.com/questions
http://www.superuser.com/faq
http://www.stackoverflow.com/faq
http://www.stackoverflow.com/questions
------EDIT------
Code to access the elements further down the data structure shown above:
my #urls;
foreach my $key1 ( keys( %{$VAR1} ) ) {
print( "$key1\n" );
foreach my $key2 ( keys( %{$VAR1->{$key1}} ) ) {
print( "\t$key2\n" );
foreach my $key3 ( keys( %{$VAR1->{$key1}{$key2}} ) ) {
print( "\t\t$key3\n" );
push #urls, keys %{$VAR1->{$key1}{$key2}{$key3}};
}
}
}
print "#urls\n";
Using the code above why do I get the following error?
Can't use string ("13238") as a HASH ref while "strict refs" in use at ....
It is not difficult, just take the second level of keys off every key in the variable:
my #urls;
for my $key (keys %$VAR1) {
push #urls, keys %{$VAR1->{$key}{'difference'}};
}
If you're struggling with dereferencing, just keep in mind that all values in a hash or array can only be a scalar value. In a multilevel hash or array the levels are just single hashes/arrays stacked on top of each other.
For example, you could do:
for my $value (values %$VAR1) {
push #urls, keys %{$value->{'difference'}};
}
Or
for my $name (keys %$VAR1) {
my $site = $VAR1->{$name};
push #urls, keys %{$site->{'difference'}};
}
..taking the route either directly over the value (a reference to a hash) or over a temporary variable, representing the value via the key. There is more to read in perldoc perldata.