Can't print contents of hash - arrays

Here's how I've set up my hash:
my #keys_i_need = qw(A B C D E F G);
my %keys_i_need = map {$_ => []} #keys_i_need;
foreach my $line (#{$file_arr_ref}) {
my $sub = substr( $line, 0, 1);
if(($sub ne "#") and ($sub ne "")){
my #key_vals = split(/\s+/, $line);
my $key = shift #key_vals;
if(exists $keys_i_need{$key}) {
INFO("key is $key value is " . join(", ", #key_vals));
push (#{$keys_i_need{$key}}, \#key_vals);
DEBUG(Dumper \%keys_i_need);
}
}
}
If I understand this correctly, it's a hash, where each value is an array reference with array references inside the array reference. I don't want to use Dumper because I want to pick out each piece.
I'm trying to read out what's been pulled into the hash but I'm getting an error message that says:
"my" variable $values masks earlier declaration in same statement at /home/rabdelaz/workspace/akatest_5/scripts/Viper/Stragglers.pl line 67.
foreach my $key (keys %$config_options) {
foreach my $arr_ref_of_arr_values (%$config_options{$key}) {
foreach my $values (#$arr_ref_of_arr_values) { #<----------line 67
foreach my $value (#$values) {
INFO("key $key has values $value");
}
}
}
}
This looks right to me. I can't quite figure out what perl is complaining about. Any thoughts?

I see what I did now.
I was confused (once again) by the fact that an array reference is a scalar and not an array. Although, as you can see from my original code I went the wrong direction any way (outside to the hash, rather than inside to the array ref. So my final code should look more like this:
foreach my $key (keys %$config_options) {
foreach my $arr_ref_of_arr_values ($$config_options{$key}) {
foreach my $values (#$arr_ref_of_arr_values) { #<----------line 67
foreach my $value (#$values) {
INFO("key $key has values $value");
}
}
}
}
In the course of debugging, I ended up with this to get the first value of the first array in the first key:
INFO("first value of first array of first key: " . ${${$$config_options{'A'}}[0]}[0]);
I then used this as my guidepost.

Related

Access the key value from an associative array

I have the associative array %cart_item, within this is a series of associative arrays. I need to access the value of the keys within %cart_item. I have the following code which iterates on each array key. (I do the equivalent of php's continue if the value is 'meta')
my $key_value;
for (keys %cart_item) {
next if (/^meta$/ || /^\s*$/);
}
I need to do something like this though (although this isn't valid), setting the value of the keys in the loop:
my $key_value;
for $i (keys %cart_item) {
next if (/^meta$/ || /^\s*$/);
$key_value = $i;
# do stuff
}
Could anyone suggest a solution here? Apologies if this is obvious, I'm a Perl newbie. Thanks
I think you are asking for
for my $key (keys %cart_item) {
next if $key =~ /^meta$/ || $key =~ /^\s*$/;
my $val = $cart_item{$key};
...
}
If you're just looking for the value that goes with the key, you can get both at the same time with each:
while (my ($key, $val) = each %cart_item) {
next if $key eq 'meta' || $key =~ /^\s*$/;
...
}
That's the equivalent of PHP's foreach ($cart_item as $key => $val).
I also changed the "meta" check to use simple string equality; no need to use a regular expression for an exact match.
Your original code has
for ( keys %cart_item ) {
next if (/^meta$/ || /^\s*$/);
}
which works fine because the for has no loop control variable so it defaults to Perl's "pronoun" it variable $_. In addition, your regex pattern matches have no object so they also default to $_
Written fully, this would be
for $_ ( keys %cart_item ) {
next if ( $_ =~ /^meta$/ || $+ =~ /^\s*$/);
}
but we don't have to write all of that. Some people hate it; others like me think it's absolute genius
Your non-working code
my $key_value;
for $i (keys %cart_item) {
next if (/^meta$/ || /^\s*$/);
$key_value = $i;
# do stuff
}
does use a loop control control variable $i (bad name for a hash key, by the way). That's all fine except that your regex matches still
my $key_value;
for $i (keys %cart_item) {
next if $i =~ /^meta$/ or $i =~ /^\s*$/;
$key_value = $i;
# do stuff
}
or, better still, stick with $_ and write this
for ( keys %cart_item ) {
next if /^meta$/ or /^\s*$/;
my $key_value = $_;
# do stuff
}

Perl - Identify all elements in a hash that have the highest value

I wrote some Perl code that searches for the highest key-value pair in a hash in which the keys are text and the values are numbers:
my $o_val = 0; # FOR TRACKING HIGHEST VALUE ENCOUNTERED IN THE LOOP
my $o_key; # FOR TRACKING CORRESPONDING KEY TO THE HIGHEST VALUE
while ( my ($key, $val) = each(%NG) ) {
if ( $val > $o_val ) {
$o_val = $val;
$o_key = $key;
}
}
print "$okey\n";
The problem is that it does nothing to account for the possibility of a tie for highest value. How can I capture all the key-value pairs that tied for highest value if my measuring variable can potentially change with each iteration of the loop?
I have the idea that I could write another while loop to run through the same hash after $o_val had been established as the highest value then push each key paired to $o_val into another array, something like:
my #highest; # ARRAY OF HIGHEST-VALUE KEYS
while ( my ($key, $val) = each(%NG) ) {
if ( $val == $o_val ) { push(#highest, $key); }
}
but this seems kinda inefficient. I'm hoping there are some Perl commands I'm not aware of that will let me identify the highest value in the hash without looping through it so I can just use the second piece of code in my question.
You can use an array to keep the keys for highest value,
if ( $val > $o_val ) {
$o_val = $val;
#o_keys = $key;
}
elsif ($val == $o_val) {
push(#o_keys, $key);
}
#!/usr/bin/env perl
use strict;
use warnings;
my %h = map { $_ => int(rand 10)} 'a' .. 'z';
# see what we've got
my #k = sort { $h{$b} <=> $h{$a} } keys %h;
print "$_ => $h{$_}\n" for #k;
# initialize $max with a value from %h
my ($max) = values %h;
# keys with highest values
my #argmax;
while (my ($k, $v) = each %h) {
next if $v < $max;
if ($v > $max) {
$max = $v;
#argmax = ($k);
}
else {
push #argmax, $k
}
}
print "#argmax\n";
print "#h{ #argmax }\n";
Of course, if you don't care much about memory, or if you are golfing, or japhing, you could write something like:
my %v;
push #{ $v{$h{$_}} }, $_ for keys %h;
my ($max) = sort { $b <=> $a } keys %v;
print "#{ $v{$max} } => $max\n"

How to pass an array as value to a single key in a hash of perl?

my %hash;
my #chain;
foreach (my $i=0; $i<=7; $i++)
{
foreach (my $j=0; $j<=($#output); $j++)
{
if ($output[$j] =~ /chain1/)
{
push (#array, $output[$j]);
}
}
$hash{$chain[$i]} = [ #array ];
}
print "$hash{$chain[0]}\n";
The problem is I am not able to assign the arrays to unique keys in the hash. when I say print all the keys print the same output.
You keep adding to the same array.
for (...) {
{
my #array; <-- Add here
for (...) {
...
push #array, $output[$j];
...
}
$hash{$chain[$i]} = \#array; <-- No need to copy elements anymore.
}
Perl hash are designed to hold only scalar values. It can have a key and the value can be the address reference of the array (which is scalar). But if the array value need to be modified concatenate the contents of the array as a string with certain delimiter and store the string as key.
Hope this Helps.

Foreach array with Perl

It seems my code cannot iterate over an array stored in a hash.
What did I miss ?
#!/usr/bin/env perl
use Data::Dumper;
my $data = {array => ['a', 'b', 'c']};
my #array = $data->{array};
print Dumper(#array); # It looks like $data->{array} is an array
print "Ref: ".ref($data->{array})."\n"; # And this array is indeed an array
foreach ($data->{array}) { print "$_\n"; } # But this doesn't work
foreach (#array) { print "$_\n"; } # Neither this one
# But with a regular array it works...
my #myNames = ('Larry', 'Curly', 'Moe');
foreach (#myNames) { print "$_\n"; }
My output:
$VAR1 = [
'a',
'b',
'c'
];
$VAR1 = 'a';
Ref: ARRAY
ARRAY(0x8002bcf8)
ARRAY(0x8002bcf8)
Larry
Curly
Moe
I am pretty confused with REF/SCALAR types. Sometime Perl takes values as references sometime not. In this case, because I get 'ARRAY' from the ref function, I guess $->{array} doesn't give me an array but a reference to the array.
I have also tried #$data->{array} without success.
$data->{array} is indeed an array reference.
To dereference it, use #{} on the reference
foreach (#{$data->{array}}) { print "$_\n"; }
Edit:
Or if you dont want to use {...} after #
my $arrayref = $data->{array};
foreach (#$arrayref ) { print "$_\n"; }

Problems with array references in perl

I am trying to count how many time DE10 and each of the keys in my ICD10 hash occurs in the same line in my file2.tsv. I further have to divide it by male/female (M/K).
I therefore made a hash called results. Each of the keys in this is named after the key in the ICD10 hash, and they refers to an array of 2 elements, the first counting the male, the second counting the females.
But I get this warning:
Can't use string ("0") as an ARRAY ref while "strict refs"
due to this line:
$results{$key}[1] +=1;
I am a little weak on this reference part, can someone help me with my mistake? thanks a lot
#!/usr/bin/perl -w
use strict;
###################
# loading my hash #
###################
my %icd10;
open(IN, '<', 'myfile.tsv') or die;
while (defined (my $line = <IN>)) {
chomp $line;
$icd10{$line} = 1;
}
close IN;
################
### COUNTING
#################
my %results;
open(IN, '<', 'myfile2.tsv') or die;
while (defined (my $line = <IN>)) {
chomp $line;
my #line = split('\t', $line);
my %hash;
for (my $i = 2; $i < scalar(#line); $i++){
$hash{$line[$i]} = 1;
}
if (grep (m/^DE10/, keys %hash)) {
foreach my $key (keys %icd10){
if (grep (m/^$key/, keys %hash)) {
if (exists $results{$key}) {
if ($line[1] eq 'M') {
$results{$key}[1] +=1;
}
elsif ($line[1] eq 'K'){
$results{$key}[2] +=1;
}
}
else{
if ($line[1] eq 'M') {
$results{$key}=(1,0);
}
elsif ($line[1] eq 'K'){
$results{$key}=(0,1);
}
}
If you want $results{$key} to be a reference to an array, then the parentheses in these two identical sentences $results{$key}=(1,0); should be square brackets, like this: $results{$key}=[1,0];.
To create a reference to an array, you can use backslash operator:
$arrayref = \#array;
To create a reference to an anonymous array you should use square brackets:
$arrayref = [ 'ele1', 'ele2' ];
See perlref for further details.

Resources