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

Hey Perl-Pros!

As a Perl-Newbie, I'm currently dealing with a programming problem and would like to hear some tipps of someone more experienced in Perl-programming. I'm trying to sort some measurements which I loaded from some SQL-tables in Perl-lists. There are lists with the following structure:

@MeasurementType = (MeasurementA, MeasurementB, Measurement C, Measure +mentB, MeasurementB,..........); @MeasurementValue = ( 1A, 3A , 3A , 2A, 5A, ……); @MeasurementTry= (1 , 1 ,1 , 2 , 3, ….); @MeasurementTime= (DateA, DateB, DateC, DateD, DateE,.....); [ All lists have the same length, since they should be seen together, +as their single elements represent the different measurements e.g..Measurement[0]= @MeasurementType[0],@MeasurementValue[0],@Measur +ementTry[0],@MeasurementDate0] I'm trying to create a list, which creates an output like: ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ [Measurement] --[1.Try (MeasurementDate, MeasurementValue]--[2. Try]-- +[3.Try] MeasurementA -- DateA, 1A -- ______-- _______ MeasurementB -- DateB, 3A -- DateD,2A -- DateE,5A MeasurementC -- DateC, 3A -- ______-- _______ +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Requirement: If there are more than one try for a measurement, the different tries should be listed next to each other in the same row.

Whats the best way to do this?
Since Perl doesn't support two-dimensional arrays, I would try to connect the seperate lists with an additional list where I save references to them. Doing so, I can use a "for each" to easily print out all measurements. Unfortunately, this will only list all measurements underneath each other. Measurements, which have been done more than one time (see MeasurementB in example) shouldn't be added as multiple rows, but as as 2nd or 3rd try in the same row from the first try. Anyone of you got an advice how to accomplish this?

Replies are listed 'Best First'.
Re: Sorting measurements
by GrandFather (Saint) on Aug 19, 2015 at 08:26 UTC
    Since Perl doesn't support two-dimensional arrays

    Um, actually Perl does:

    #!/usr/bin/perl use strict; use warnings; my @twoDArray = ( [1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12, 13] ); # Avoiding indexes for my $rows (@twoDArray) { for my $value (@$rows) { print "$value "; } print "\n"; } print "\n"; # Using indexes for my $rIdx (0 .. $#twoDArray) { for my $vIdx (0 .. $#{$twoDArray[$rIdx]}) { print "$twoDArray[$rIdx][$vIdx] "; } print "\n"; }

    Prints:

    1 2 3 4 5 6 7 8 9 10 11 12 13 1 2 3 4 5 6 7 8 9 10 11 12 13

    In fact Perl supports as many dimensions as you want and actually allows mixtures of arrays, hashes and various scalar types as well in arrays.

    Premature optimization is the root of all job security
      ... Perl supports as many dimensions as you want and actually allows mixtures of arrays, hashes and various scalar types as well in arrays.

      Jenny1990: Please see perldsc, perllol. (Update: Oops, RichardK beat me to one of these — should have read everything before posting!)


      Give a man a fish:  <%-{-{-{-<

      When I was first learning perl, I read that "perl does not support two dimensional arrays". (Sorry I do not remember where) I was confused because I had examples of source code which clearly used them. I now consider the discrepancy to be one of viewpoint. Perl does not have a data type similar to the multidimensional array of other languages. Perl does provide an alternate indexing syntax which allows us to use an array-of-arrays exactly as if it were a two-dimensional array. I do not think it matters how the support is implemented. GrandFather has shown us that it is available and how to use it.
      Bill
Re: Sorting measurements
by RichardK (Parson) on Aug 19, 2015 at 11:45 UTC

    perldsc - Perl Data Structures Cookbook, is a great reference for complex data structures, it's well worth a read. It contains lots of advice & examples, and should help you with your problem.

    BTW, perl ships with lots of documentation, try 'perldoc perl' for a starting point.

Re: Sorting measurements
by 1nickt (Canon) on Aug 19, 2015 at 08:57 UTC

    Hi Jenny1990, it's hard to follow what you are trying to do. Can you please post a stripped-down version of your code?

    You probably need to build up a hash data structure. You could either do a complex SQL query on several tables, or you could build up your data structure as you read the rows from each table.

    Your data might look like this after you've built it:

    my $measurements = { 'MeasurementA' => { 1 => { 'Date' => 'DateA', 'Value' => '1A', }, }, 'MeasurementB' => { 1 => { 'Date' => 'DateB', 'Value' => '3A', }, 2 => { 'Date' => 'DateD', 'Value' => '2A', }, 3 => { 'Date' => 'DateE', 'Value' => '5A', }, }, 'MeasurementC' => { 1 => { 'Date' => 'DateC', 'Value' => '3A', }, }, };

    And then you can use it to produce your report:

    foreach my $measurement ( sort keys %{ $measurements } ) { print "Measurement: $measurement\n"; foreach my $try ( sort keys %{ $measurements->{ $measurement } } ) { + print " Try: $try\n"; print " Date: $measurements->{ $measurement }->{ $try }->{'Dat +e'}\n"; print " Value: $measurements->{ $measurement }->{ $try }->{'Val +ue'}\n"; } }

    Outputs:

    Measurement: MeasurementA Try: 1 Date: DateA Value: 1A Measurement: MeasurementB Try: 1 Date: DateB Value: 3A Try: 2 Date: DateD Value: 2A Try: 3 Date: DateE Value: 5A Measurement: MeasurementC Try: 1 Date: DateC Value: 3A

    Or,

    foreach my $measurement ( sort keys %{ $measurements } ) { print "$measurement -- "; foreach my $try ( sort keys %{ $measurements->{ $measurement } } ) { + print "$measurements->{ $measurement }->{ $try }->{'Date'}: $measu +rements->{ $measurement }->{ $try }->{'Value'} "; last if $try == scalar keys %{ $measurements->{ $measurement } }; print " -- "; } print "\n"; }

    Outputs:

    MeasurementA -- DateA: 1A MeasurementB -- DateB: 3A -- DateD: 2A -- DateE: 5A MeasurementC -- DateC: 3A

    But first you'll have to build your data structure.

    The way forward always starts with a minimal test.
Re: Sorting measurements
by anonymized user 468275 (Curate) on Aug 19, 2015 at 09:27 UTC
    Hi Jenny, To terminate a line of output and start the next line, you print "\n". In this case you only want to do that when the tries are exhausted and otherwise a tab or space separator. e.g.:
    for (my $i = 0; $i <= $#MeasurementType; $i++) { my $toTry = $MeasurementTry[$i]; while ($toTry) { print "$MeasurementType[$i] " . "-- " . "$MeasurementDate[$i], " . "Oops "; print --$toTry ? "\t" : "\n"; } }
    I put "Oops" instead of the measurement value because I am presuming there are different values per try, otherwise more than one try would be redundant, but you have only one value per measurement type. Perhaps you need an array of array for the values as another poster has suggested. If so, you'll also need to index through them per inner loop.

    The last print statement I put in may seem harder to read -- it's a shorthand for the following logic: "decrement $toTry, then print tab if there are still tries left else print cr" - You'll probably have to change that anyway when you re-organise the values array.

    One world, one people

Re: Sorting measurements
by james28909 (Deacon) on Aug 19, 2015 at 08:42 UTC
    Here is something I just came up with, it isnt formatted the way you wanted but I think it will work:
    use strict; #use warnings; turned off for redundant printf warning my @MeasurementType = sort qw(MeasurementA MeasurementB MeasurementC M +easurementB MeasurementB); my @MeasurementValue = sort qw(1A 3A 3A 2A 5A); my @MeasurementTry= sort qw(1 1 1 2 3); my @MeasurementTime= sort qw(DateA DateB DateC DateD DateE); my $size = @MeasurementTry - 1; print ("MeasurementType | MeasurementValue | MeasurementTry | Mea +surementTime\n"); print ("----------------|-----------------------|----------------|---- +------------\n"); for ( my $i = 0 ; $i <= $size ; $i++ ) { printf ("%-22s %-15s %-9s %-0s\n", ("$MeasurementType[$i]\t|", "$MeasurementValue[$i] \t|", "$MeasurementTry[$i]\t |", "$MeasurementTime[$i]")); }
    Im not really clear on a few things like value "1A" or "3A" go with type "MeasuemantA" ect ?

    Outputs:

    MeasurementType | MeasurementValue | MeasurementTry | Measurement +Time ----------------|-----------------------|----------------|------------ +---- MeasurementA | 1A | 1 | DateA MeasurementB | 2A | 1 | DateB MeasurementB | 3A | 1 | DateC MeasurementB | 3A | 2 | DateD MeasurementC | 5A | 3 | DateE
    EDIT: Updated code with some kind of formatting.
Re: Sorting measurements
by Anonymous Monk on Aug 19, 2015 at 12:15 UTC
    Also: use ORDER BY in your query.