Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations bkrike on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

hash/array analysis 2

Status
Not open for further replies.

chazoid

Technical User
Dec 2, 2002
300
US
It's been a long week, and I'm having some trouble wrapping my brain around this one..

I have a series of records in an array:
[tt]
C001,AAAA,ADDR
C002,AAAA,ADDR
C003,BBBB,ADDR
C004,CCCC,ADDR
C005,DDDD,ADDR
C006,DDDD,ADDR
C007,DDDD,ADDR
[/tt]
I want to put this into a hash of arrays with the first column as the key, then add an additional item to the array - it should end up structured like this:
[tt]
C001 => AAAA,ADDR,1 of 2
C002 => AAAA,ADDR,2 of 2
C003 => BBBB,ADDR,1 of 1
C004 => CCCC,ADDR,1 of 1
C005 => DDDD,ADDR,1 of 3
C006 => DDDD,ADDR,2 of 3
C007 => DDDD,ADDR,3 of 3
[/tt]
The duplicate values will always be consecutive in the original data, but I need to keep the relationship between the key/value so that C002 won't get "1 of 2" and C001 gets "2 of 2". Due to the random ordering of hashes, maybe an array of arrays would be better here? To create the 1 of n, I'm thinking a second hash would be needed to keep track of duplicates.
Any suggestions would be appreciated.. it's mainly the logic I'm having trouble with - I also don't have much experience accessing data structures like this, but I think I can figure that part out.

Thanks!

- jt
 
Well, to split up the array into hash keys, I would:
Code:
foreach $record (@array){
($hkey,$val1,val2)=split(/,/,$record);
$hash{$hkey}=[$val1,$val2];
}

Err, I think that anonymous data structure for the array will work.

Im not sure you could count them on the fly like that, but you might be able to do some instance comparisons after the fact and add them to a new hash.
 
This code is kind of ugly, it was done in a hurry, but it should work for you. The last field that is added on is based on the AAAA/BBBB field, but does not take into account the ADDR field.

@array contains your records.

Code:
my (@array, @temp, %hash);
my $last = 0;

foreach (@array) {
    if (${$_}[1] ne $last && !(scalar @temp)) {
        push @temp, [@{$_}];
        $last = ${$_}[1];
    }  elsif (${$_}[1] eq $last) {
        push @temp, [@{$_}];
    } else {
        for (my $i = 0; $i <= $#temp; $i++) {
            my $key = shift @{$temp[$i]};
            $hash{$key} = [@{$temp[$i]}, ($i + 1) . " of " . ($#temp + 1)];
        }
        @temp = ();
        push @temp, [@{$_}];
        $last = ${$_}[1];
    }
}
for (my $i = 0; $i <= $#temp; $i++) {
    my $key = shift @{$temp[$i]};
    $hash{$key} = [@{$temp[$i]}, ($i + 1) . " of " . ($#temp + 1)];
}

foreach (sort keys %hash) {
    print "$_ - ", join("," , @{$hash{$_}}), "\n";
}
 
Thanks for the suggestions.. rharsh, I tried your code, but only ended up with '- 7 of 7' I haven't had a chance to look into it yet though.
 
Here's what I ended up doing if anyone is interested - the purpose of this is to create numbering for cd-rom labels when data spans multiple CD's - duplicate values in the second column indicate the data has overflowed to multiple CD's

Code:
#array of arrays
my @cdInfo = (["C001","AAAA","ADDR"],
              ["C002","AAAA","ADDR"],
              ["C003","BBBB","ADDR"],
              ["C004","CCCC","ADDR"],
              ["C005","DDDD","ADDR"],
              ["C006","DDDD","ADDR"],
              ["C007","DDDD","ADDR"],
             );


CDnumbering(\@cdInfo);

sub CDnumbering {

    my $cdInfo = shift @_;
    my (%cdCounts);
    my @temp;

    foreach my $record (@cdInfo){
        my $HG  = $record->[1];
        if (exists $cdCounts{$HG}){
            my $i = $cdCounts{$HG};
            $i++;
            $cdCounts{$HG} = $i;
        }
        else {
            $cdCounts{$HG} = 1;
        }
    }

    foreach my $HG (keys %cdCounts){
        my $cdTotal = $cdCounts{$HG};
        my $i = 1;
        foreach my $record (@cdInfo){
            if ($record->[1] eq $HG){
                push @{ $record },"$i of $cdTotal";
                $i++;
            }
        }
    }
}

Data::Dumper output:
Code:
$VAR1 = [
          [
            'C001',
            'AAAA',
            'ADDR',
            '1 of 2'
          ],
          [
            'C002',
            'AAAA',
            'ADDR',
            '2 of 2'
          ],
          [
            'C003',
            'BBBB',
            'ADDR',
            '1 of 1'
          ],
          [
            'C004',
            'CCCC',
            'ADDR',
            '1 of 1'
          ],
          [
            'C005',
            'DDDD',
            'ADDR',
            '1 of 3'
          ],
          [
            'C006',
            'DDDD',
            'ADDR',
            '2 of 3'
          ],
          [
            'C007',
            'DDDD',
            'ADDR',
            '3 of 3'
          ]
        ];
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top