1

When reading an array (actually an array of arrays) from a hash table, there seems to be an extra level in the data structure. I fill the array from a file as such.

open(my $fh, '<', $newfile) or next; 
while (my $line = <$fh>)  
{ 
    my @job = split /\s+/, $line;
    push @userjobs, [ @job ];               
}
close ($fh);

userjobs has a size of three as expected, from the file, and I add it to the %crontab hash

$crontab{$user} = [ @userjobs ];

When I attempt to read the user jobs back the size is 1

my @temp = $crontab{$user};

Looking at Dumper shows an extra level in the hash table value hierarchy. I can access the hash table through something like $crontab{$user}[0][0]. However, now I want to add a 4th userjob, but I can't access the underlying job array. Adding push @temp, [ @newjob ] adds it to the additional level, but not the job array. Any idea what I'm doing wrong?

3
  • Probably you have intended to use push @userjobs, \@job; - push into array reference to another array (@job)? Commented Mar 18, 2020 at 23:38
  • Show us the Data::Dumper output. Commented Mar 18, 2020 at 23:42
  • What is content of your input file? We can not read what is in your mind or files. You should provide sample of input data. Use [Data::Dumper] to investigate structure of %crontab you have generated -- post output so we knew what you deal with. Commented Mar 19, 2020 at 0:13

4 Answers 4

3

You are adding an array reference to the hash:

$crontab{$user} = [ @userjobs ];

If you want to access the array, you need to dereference it:

my @temp = @{ $crontab{$user} };

Note that this technique potentially implies a hash copy. It might be more efficient to do:

$crontab{$user} = \@userjobs;
Sign up to request clarification or add additional context in comments.

Comments

2

Question is not very clear on desired structure of %crontab hash.

Following piece of code is based on best guess that %crontab hash will have username as a key and jobs will be stored in array referenced by value associated with the key (username).

NOTE: change $debug = 1 to view %crontab hash structure

use strict;
use warnings;
use feature 'say';

use Data::Dumper;

my $debug = 0;

my %crontab;

while(<DATA>) {
    my($user,@jobs) = split '\s+';

    push @{$crontab{$user}}, @jobs;
}

say Dumper(\%crontab) if $debug;

while( my($k,$v) = each %crontab ) {
    say 'User: ' . $k . ' => ' . join ' ', @{$v};
}

__DATA__
user1 job1 job2 job3
user2 job1 job2 job3 job4 job5
user3 job1 job2 job3 job4
user4 job1

Comments

2

The value of hash elements are scalars, so $crontab{$user} is a scalar (containing a reference to an array), so are assigning a single scalar to @temp. Replace

my @temp = $crontab{$user};

print(Dumper(\@temp));

for (@temp) { ... }

with

my $temp = $crontab{$user};

print(Dumper($temp));

for (@$temp) { ... }

Comments

1

Heh, I think I just answered a similar problem in How to print the values of array reference in perl? . You are assigning an array reference to a named array. Since the reference is a scalar (a single value), you get an array of one value that is the reference. Now you have an array of arrays:

my @temp = $array_reference; # likely wrong.

This is the same as creating a list of one element and assigning that to @temp:

my @temp = ( [ ... ] );

That's where your extra level comes in. The first level is for @temp. You access $temp[0] to get to the first item in the array, which is the reference. Now, you need to get to elements in that reference, so that's your second level: $temp[0][0].

Since all references are scalars, you likely wanted to assign to a scalar:

my $temp = $array_reference;

Now that's just the reference with no extra array wrapper around it so you can access its first element as $temp[0]. Since all hash values are scalars, that's probably how you want to assign it:

my $temp = $crontab{$user};     # whole ref
my $first = $crontab{$user}[0]; # just first element

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.