fasoli has asked for the wisdom of the Perl Monks concerning the following question:

Hi all, I am hoping to get some feedback on what has troubled me for over a week now. I'm trying to open a bunch of files (I'm using four files as a test case) and read their contents into 2D arrays. The files looks like this:

1 2 3 4 5 6 7 8 9

I've written a script to open the files, read them line by line and then split them. When I try to print element [0][1] from each matrix in each file, I get the same number four times. This number is indeed element [0][1] but only from the first file, it's as if it ignores the rest of the files. Does anyone have any idea why this is wrong?

#/bin/perl/ use strict; use warnings; use autodie; my $molec = "1ac6"; my $cluster; my $times; my $input; my @list; my $list; my $line; my $path = "/media/RAIDstorage/home/athina/dist-analysis/${molec}/time +series/test"; my @files; @files = `ls $path\/$molec-times*`; foreach (@files) { /${molec}-times-(\d+)-clust(\d{1})/; $times = $1; $cluster = $2; open $input, '<', "$path\/${molec}-times-${times}-clust${cluster}.ou +t" or die $!; while ($line = <$input>) { chomp $line; #next unless $. > 4; push @list, [split/\s+/, $line]; }#while close $input; print "$list[0][1] \n"; }#foreach

Replies are listed 'Best First'.
Re: read files into 2D arrays and print element?
by BrowserUk (Patriarch) on Nov 29, 2016 at 17:01 UTC
    When I try to print element [0]1 from each matrix in each file, ... Does anyone have any idea why this is wrong?

    @list is declared outside your for loop, so you are accumulating the data for all the files into the array; thus whatever value you put into $list[0][1] first, will never change.

    If you move the declaration of @list inside the for loop, you'll probably get what you want.


    With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority". The enemy of (IT) success is complexity.
    In the absence of evidence, opinion is indistinguishable from prejudice.
      Oh!!! Thanks so much!
Re: read files into 2D arrays and print element?
by haukex (Archbishop) on Nov 29, 2016 at 17:08 UTC

    Hi fasoli,

    BrowserUk and LanX already gave you some solutions, I just had a few other suggestions for your code:

    Note that you write /${molec}-times-(\d+)-clust(\d{1})/;, but then you don't check whether the match succeeded (e.g. /.../ or die "Didn't match filename $_";), if it didn't then the variables $1, $2 etc. won't be updated! Try printing out the filename "$path\/${molec}-times-${times}-clust${cluster}.out" to ensure that you're generating the correct filename (probably easiest to store the filename in a variable first).

    A few more: use glob instead of `ls ...`, and only declare your variables in the scope where they're actually needed, otherwise they're hardly any better than globals (open my $input, ..., while (my $line = <$input>), etc.).

    Hope this helps,
    -- Hauke D

      Oh good point, I normally do put in an if clause to check for the matching, I forgot. But yes I did print the path and the filenames first. Thanks for picking it up! :)

Re: read files into 2D arrays and print element?
by LanX (Saint) on Nov 29, 2016 at 17:05 UTC
    you are pushing your matrices successively into the same @list for all files.

    print $list[3*$n][0] to get the upper left element from matrix $n (starting with 0)

    Please next time indent your code properly, it's not nice to force us struggling thru this.

    Cheers Rolf
    (addicted to the Perl Programming Language and ☆☆☆☆ :)
    Je suis Charlie!

      I'm sorry about the lack of indentation - I don't know how to indent and, you'll probably be shocked by this, but this is actually me doing a good job at indenting... It's crap I know, it also makes me struggle. All I wanted to say with this is that this wasn't lazy formatting, this was just me not having a clue.

      I've tried to understand it but it goes over my head as all the tips I've read are probably more intuitive rather than explanatory, or they assume certain fluency in perl/general programming. I apologise for the bad formatting, I need to learn how to do it at some stage.

        Essentially, any time you are operating in a block (typically defined by statements that use { and } to denote a block), you indent a single time:

        for (@things){ # this is a block. indent once if ($_ eq 'blah'){ # this is an inner block, indent twice while (1){ # 2nd level inner block # indent three times } if (0){ # another 2nd level inner block } # back in 1st inner block } # back in outer block } # back to top level

        In that case you could do a lot worse than perltidy.

        > I don't know how to indent

        My editor does it for me, which one do you use?

        I'm sure you'll find someone here telling you how to do it there.

        Cheers Rolf
        (addicted to the Perl Programming Language and ☆☆☆☆ :)
        Je suis Charlie!

Re: read files into 2D arrays and print element?
by fasoli (Beadle) on Nov 30, 2016 at 17:45 UTC

    Hi again all. Thanks to your help I solved my first problem, thank you again. Now what I'm trying to do is get the average value of my four matrices' elements (to then proceed to getting the standard deviation). They are four 3x3 test matrices, each one in a different file. They are test cases as my real matrices are thousands of lines long and the number of files is again thousands.

    When I print them with  $line[$a][$b] they look correct, so I've commented this line out as it was used as a test to see if they look ok. The output I'm getting if I try to get the sum of the elements and then the mean, is  Use of uninitialized value in addition (+) at test_SD_Wednesday.pl line 52 and a bunch of wrong numbers as sum/averages. I'm pretty sure I'm screwing something up badly but I can't figure out what. Any hints please? I'm starting to get scared my supervisors will really shout at me or think I'm an idiot if I tell them it's taken me 10 days to have a script that doesn't work...

    Finally can someone comment on the indentation? Does it make sense they way I did it? It looks less messy but no clue if I got the philosophy behind it.

    #/bin/perl/ use strict; use warnings; use autodie; my $molec = "1ac6"; my $cluster; my $times; my $input; my $path = "/media/RAIDstorage/home/athina/dist-analysis/${molec}/time +series/test"; my $line; my @files; @files = `ls $path\/$molec-times*`; foreach (@files) { my $a; my $b; my $m_avrg; my @m_avrg; undef @m_avrg; my @list; my $list; my $aver; /${molec}-times-(\d+)-clust(\d{1})/; $times = $1; $cluster = $2; open $input, '<', "$path\/${molec}-times-${times}-clust${cluster}.out +" or die $!; while ($line = <$input>) { chomp $line; push @list, [split/\s+/, $line]; } # while input close $input; for ($a=0; $a<=2; $a++) { for ($b=0; $b<=2; $b++) { #print "$list[$a][$b] "; # check matrices $m_avrg[$a][$b] = ($m_avrg[$a][$b] + $list[$a][$b]); print "$m_avrg[$a][$b] \n"; } print " \n"; } print "average\n"; for ($a=0; $a<=2; $a++) { for ($b=0; $b<=2; $b++) { $m_avrg[$a][$b] = $m_avrg[$a][$b] / 4; print "$m_avrg[$a][$b] "; } print "\n"; } } # foreach file in loop