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

Bows to the Perl Monks How do I loop through many arrays and on each loop I have to make a math function call. If I had one array I would loop through like below. But if I have 3 arrays or more like:

@array1=(1,2,3,4,8); @array2=(1,4,2,4,5); @array3=(1,6,1,7,5);

I want to loop through each array and see which one have the largest value at each index. What is the most efficient way of doing this please? Thank you very much for your help in advance.

SORRY UPDATE I probably didnt make this clear I was looking for at each index from each array 1,2,3 the largest value and which array had this largest value eg: index0: @array1,@array2,@array3 equal index2: @array3 index3: @array1 index4: @array3 index5: @array1 Apologizies for the inconvenience and thank you to those who responded.....

ONE ARRAY EXAMPLE:

@array=(1,2,3,4,5); foreach $element (@array){ chomp $element; if ($element == 1){ ##do something; } }

Replies are listed 'Best First'.
Re: how to loop through many arrays
by toolic (Bishop) on Jun 19, 2011 at 01:23 UTC
    You could just add all array variables to your foreach loop:
    use warnings; use strict; my @array1=(1,2,3,4,8); my @array2=(1,4,2,4,5); my @array3=(1,6,1,7,5); foreach my $element (@array1, @array2, @array3){ if ($element == 1){ ##do something; } }
    Perl has many tools for operating on arrays:

    Update: my solution was posted before the OP's UPDATE.

      thanks for your help
Re: how to loop through many arrays
by davido (Cardinal) on Jun 19, 2011 at 02:54 UTC

    Problem: Iterate over each array in parallel (in other words, treat each array as a column, and each index as a row). For each row, find the max value among the columns, and report that max along with which column or columns have that value.

    One possible solution: I created a subroutine named get_max_and_column_list_per_row(), which is a really awkward name, but it does pretty much exactly what you're asking for:

    Pass it a list of array references (a LOL: perllol). The function evaluates each row (each outer index) to find the max value in that row's columns. It also keeps track of which columns that max was found in. It constructs an array in original row order. That array consists of an anonymous hash. The key is that max value found for the given row. The value is an anonymous array of the column numbers that contained that max value. Clear as mud. :)

    use Modern::Perl; use List::Util qw( max ); # Build a sample dataset of ten rows of ten columns each, # with random numbers between zero and nine. my @lists = map { [ map { int( rand( 10 ) ) } 1 .. 10 ] } 1 .. 10; # Invoke our dirty little function to get the list # of maxes per row, and columns that hit that max. my @max_indices = get_max_and_column_list_per_row( @lists ); # Print our list out nicely. { local $" = ", "; foreach my $row_index ( 0 .. $#max_indices ) { my ( $max, $columns ) = each %{ $max_indices [ $row_index ] }; say "Row $row_index has a max of $max in column(s) @{$col +umns}"; } } # The ugly function. Accepts a LoL, returns a LoHoL. sub get_max_and_column_list_per_row { my( @arrays ) = @_; # First, find out how many columns we have. my $top_index = max( map $#{$_}, @arrays ); # The rest is a big map{}. return map { my $outer_index = $_; my $current_max = max( @{ $lists[$outer_index] } ); +{ # Anonymous hash constructor. $current_max => [ grep { $lists[$outer_index][$_] == $current_max } 0 .. $top_index ] } # End of anonymous hash constructor. } 0 .. $#lists; }

    Sample output:

    Row 0 has a max of 9 in column(s) 2, 5 Row 1 has a max of 7 in column(s) 7, 9 Row 2 has a max of 7 in column(s) 6 Row 3 has a max of 9 in column(s) 1 Row 4 has a max of 9 in column(s) 3 Row 5 has a max of 9 in column(s) 8 Row 6 has a max of 6 in column(s) 5, 6, 7, 8 Row 7 has a max of 9 in column(s) 7 Row 8 has a max of 8 in column(s) 0 Row 9 has a max of 9 in column(s) 0

    Your output will vary because the dataset is built up with random numbers.


    Dave

      thanks for your help!
Re: how to loop through many arrays
by wind (Priest) on Jun 19, 2011 at 02:54 UTC

    My only advice is to just do it. You can compile the arrays into a list of arrays, or you could add them to a hash where you give each a name. Either way, just iterate on each array and use List::Util->reduce to determine the position of the max element.

    use List::Util qw(reduce); use strict; use warnings; my @array1 = (1,2,3,4,8); my @array2 = (1,4,2,4,5); my @array3 = (1,6,1,7,5); for my $array (\@array1, \@array2, \@array3) { my $max_pos = reduce {$array->[$b] > $array->[$a] ? $b : $a} keys +@$array; print "Max is $array->[$max_pos] at position $max_pos\n"; } =prints Max is 8 at position 4 Max is 5 at position 4 Max is 7 at position 3 =cut
      thanks for your help much appreciated!
Re: how to loop through many arrays
by Marshall (Canon) on Jun 19, 2011 at 05:24 UTC
    I think you are looking for the maximum of each column?
    Perl operates easiest on rows. So one way to do this is to transpose the 2-D array, i.e. make the columns become rows. Here is how to do that...

    Update: updated code to do what I think op is asking for..used wind's row code with List::Util::reduce() for a transposed "column".

    #!/usr/bin/perl -w use strict; use List::Util qw(reduce max); my @array1=(1,2,3,4,8); my @array2=(1,4,2,4,5); my @array3=(1,6,1,7,5); my @AoA = (\@array1,\@array2,\@array3); my @transposed; print "Original array:\n"; printAoA(\@AoA); ## tranpose array to make it easy to do column operations ## i.e. columns become rows foreach my $rowref (@AoA) { my $i=0; foreach my $num (@$rowref) { push @{$transposed[$i++]}, $num; } } ## Now @transposed is an array of references to what used to be ## columns. print "\nMaximum of each column...\n". "coordinates based on row 0..n, col 0..n\n"; my $col=0; foreach my $colref (@transposed) { ## you could have a loop: foreach my $num (@$colref) {} here ## below is wind's use of reduce to get the column position of ## the first maximum, perhaps you have something different in ## mind? my $max_pos = reduce {$colref->[$b] > $colref->[$a] ? $b : $a} (0. +.@$colref-1); print "Max of column index $col is $colref->[$max_pos] at array in +dex $max_pos\n"; $col++; } print "\nTransposed array:\n"; printAoA(\@transposed); sub printAoA { my $refAoA = shift; foreach my $rowref (@$refAoA) { print join(",",@$rowref),"\n"; } } __END__ Original array: 1,2,3,4,8 1,4,2,4,5 1,6,1,7,5 Maximum of each column... coordinates based on row 0..n, col 0..n Max of column index 0 is 1 at array index 0 Max of column index 1 is 6 at array index 2 Max of column index 2 is 3 at array index 0 Max of column index 3 is 7 at array index 2 Max of column index 4 is 8 at array index 0 Transposed array: 1,1,1 2,4,6 3,2,1 4,4,7 8,5,5

      This is incredible, thanks so much!

Re: how to loop through many arrays
by ambrus (Abbot) on Jun 19, 2011 at 10:38 UTC

      Thanks ambrus for the link, the comparing 2 arrays is very useful code and I will be making use of it soon