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

Hi Monks, I am working on the problem below. I have written my initial code, input and output i require. I am getting trouble to flag the starts which are not always 1 for a particular record.
Start means (Example) ########################## 158146 158367 i 11,peter,JJ113952 135588 136297 8 12,peter,JJ113952 135356 135449 3 13,peter,JJ113952 In this start means this record which comes first 158146 158367 i 11,peter,JJ113952 and End means this record which comes last 135356 135449 3 13,peter,JJ113952 ########################## Unique means this record 62556 63635 y 1,andrew,JJ113954
which occurs only once.
#!/usr/bin/perl -w use strict; use Data::Dumper; my @DB; my %hash; open(FH, $ARGV[0]) || die("Cannot open:$!"); while (<FH>) { my($n1,$n2,$letter,$ordinal,$name,$code) = (my @record = split(/[\s,]+/,$_)); push (@DB, [@record]); push (@{$hash{"$name$code"}},$ordinal); } foreach my $name_code (keys %hash) { @{$hash{$name_code}}= sort{$a<=>$b} @{$hash{$name_code}}; } @DB = sort by_weird_sort_order @DB; #optional sort foreach my $line (@DB) { my($n1,$n2,$letter,$ordinal,$name,$code) = @$line; $ordinal = "U" if @{$hash{"$name$code"}} == 1; $ordinal = "T" if ( @{$hash{"$name$code"}}>1 and (@{$hash{"$name$code"}})[-1] == $ordinal ); printf STDOUT ("%-7s %-7s %-3s %s,%s,%s\n", $n1,$n2,$letter,$ordinal,$name,$code); } sub by_weird_sort_order { my ($a_ordinal,$a_name) = (@$a)[3,4]; my ($b_ordinal,$b_name) = (@$b)[3,4]; $a_name cmp $b_name or $b_ordinal <=> $a_ordinal } __DATA__ #62556 63635 y 1,andrew,JJ113954 #126185 126699 s 2,austin,JJ113956 #441474 441538 b 3,catherine,JJ029490 #442666 442843 9 4,catherine,JJ029490 #445778 445905 0 5,catherine,JJ029490 #446059 446273 l 6,catherine,JJ029490 #450319 450379 f 7,catherine,JJ029490 #81099 81630 y 8,flintoff,JJ113952 #68766 69005 j 9,morgan,JJ113955 #63868 63897 h 10,morgan,JJ113955 #158146 158367 i 11,peter,JJ113952 #135588 136297 8 12,peter,JJ113952 #135356 135449 3 13,peter,JJ113952 output should be like this ########## 62556 63635 y U,andrew,JJ113954 63868 63897 h S,morgan,JJ113955 68766 69005 j T,morgan,JJ113955 81099 81630 y U,flintoff,JJ113952 126185 126699 s U,austin,JJ113956 135356 135449 3 S,peter,JJ113952 135588 136297 8 M,peter,JJ113952 158146 158367 i T,peter,JJ113952 441474 441538 b S,catherine,JJ029490 442666 442843 9 M,catherine,JJ029490 445778 445905 0 M,catherine,JJ029490 446059 446273 l M,catherine,JJ029490 450319 450379 f T,catherine,JJ029490
Thanks

Replies are listed 'Best First'.
Re: Creating Flags
by ig (Vicar) on Sep 01, 2009 at 05:13 UTC

    I would organize the program around the organization of data you need to achieve. Learning to do this takes practice and also learning from the examples of others.

    You need to group your data according to the name in each record. Hashes are good for grouping data. I would first build a hash, keyed by name, containing an array of all the records for each name. It would be convenient to split the record into fields at this stage, pretty much as you are doing, so this will result in a hash (keyed by name) of arrays (records) of arrays (fields). The difference from your current approach is that you have an array of all the records and a hash of arrays containing only the ordinals. I would merge these into one hash or arrays of arrays.

    Having grouped the data, I would then sort it, modify the ordinals and print the results. You already have a loop that iterates over the keys of a hash, so you know how to do that. You can easily sort the keys if you need to by using sort keys %hash instead of just keys %hash.

    Each hash element is a reference to an array. You are already working with array references in @DB, so you know how to do that. You need to sort this array according to the original ordinal, but remember that each array element is itself an array reference (a reference to the array of field values). But, again, you have already dealt with this situation in your subroutine by_weird_sort_order(), so you can probably see how to do this. Since the sort by name is already done (the outer loop iterating over the hash keys), you only need to sort by ordinal.

    Once your array of records is sorted, you need to set the ordinals to 'S', 'M' or 'T'. I can think of several ways to do this and none of them are as simple as I would like. Probably the easiest is to save the sorted list (my @sorted = sort ...), then set the ordinal of all the records to 'M', then set the ordinal of the first to 'S' and that of the last to 'T', then output them all.

    I probably haven't explained this very well, but I hope this gives you some ideas to progress with your program. You could incorporate the ideas of the last section into your existing program if you don't want to reorganize it as much as I would.

Re: Creating Flags
by jwkrahn (Abbot) on Sep 01, 2009 at 04:57 UTC
    my($n1,$n2,$letter,$ordinal,$name,$code) = (my @record = split(/[\s,]+/,$_)); push (@DB, [@record]);

    You are needlessly copying the array to a new array:

    my ( $n1, $n2, $letter, $ordinal, $name, $code ) = my @record = split /[\s,]+/; push @DB, \@record;

    (@{$hash{"$name$code"}})[-1]

    That is usually written as $hash{"$name$code"}[-1].   You are needlessly copying the array to a list.


    my ($a_ordinal,$a_name) = (@$a)[3,4]; my ($b_ordinal,$b_name) = (@$b)[3,4];

    Again, you are needlessly copying the array to a list.   That is better written as:

    my ( $a_ordinal, $a_name ) = @{ $a }[ 3, 4 ]; my ( $b_ordinal, $b_name ) = @{ $b }[ 3, 4 ];

Re: Creating Flags
by Anonymous Monk on Sep 01, 2009 at 03:43 UTC
    Can you explain what defines starts?