tags:

views:

233

answers:

3

Database Data:

Passport_No  Bank      statement_no   Credit_id 

4126897     HSBC       2948608         0
4126897     HSBC       2948609         1   
4126858     HSBC       2948591         0  
4126858     barclays   2948595         0
4126858     barclays   2948596         1
4126858     barclays   2948597         2

The credit id is based on bank.

Credit_id (this I need to fill) with 0,1,2,3,4

I was trying to automate like this

 if ($credit{$passport_no}{$bank}) { 
  $credit{$passport_no}{$bank}->{$statement}++;
 } else { 
      $credit{$passport_no}{$bank}->{$statement} = 0;
 }

and I got the out put like:

VAR1 = '4126897';
$VAR2 = {
          'HSBC' => {
                        '2948608' => 0,
                        '2948609' => '1'
                      }
        };
$VAR3 = '4126858';
$VAR4 = {
          'HSBC' => {
                           '2948591' => 0
                         },
          'barclays' => {
                               '2948595' => 0,
                               '2948596' => '1',
                               '2948597' => '1'
                             }
        };

but I was looking for

VAR1 = '4126897';
$VAR2 = {
          'HSBC' => {
                        '2948608' => 0,
                        '2948609' => 1
                      }
        };
$VAR3 = '4126858';
$VAR4 = {
          'HSBC' => {
                           '2948591' => 0
                         },
          'barclays' => {
                               '2948595' => 0,
                               '2948596' => 1,
                               '2948597' => 2
                             }
        };

How resolve this?

+1  A: 

It seems odd that you don't want to set the variable to 1 when you first see a new combination of passport number, bank and statement number:

Taking your code, I used:

#!/bin/perl -w
use strict;
use Data::Dumper;

my %credit;

while (<>)
{
        my($passport_no,$bank,$statement) = split / /;
        if ($credit{$passport_no}{$bank}) {
                $credit{$passport_no}{$bank}->{$statement}++;
        } else {
                $credit{$passport_no}{$bank}->{$statement} = 0;
        }
}

print Dumper(%credit);

I wrote a data file (called data.file):

4126897 HSBC 2948608 13.23
4126897 HSBC 2948609 23.23
4126897 HSBC 2948609 33.23
4126858 HSBC 2948591 43.23
4126858 Barclays 2948595 53.23
4126858 Barclays 2948596 63.23
4126858 Barclays 2948596 73.23
4126858 Barclays 2948597 83.23
4126858 Barclays 2948597 93.23
4126858 Barclays 2948597 14.23

And, with Perl 5.10.0 as distributed with Snow Leopard (MacOS X 10.6.1), I got:

$VAR1 = '4126858';
$VAR2 = {
          'Barclays' => {
                          '2948596' => 2,
                          '2948595' => 0,
                          '2948597' => 3
                        },
          'HSBC' => {
                      '2948591' => 0
                    }
        };
$VAR3 = '4126897';
$VAR4 = {
          'HSBC' => {
                      '2948608' => 0,
                      '2948609' => 2
                    }
        };

This is clearly very close to what you have as a test case.

Now, you have not clearly explained what concerns you about the output. AFAICS, the only difference between what you got and what you wanted was the absence of some quotes around some of the values.

I think you should adopt a Perl-ish combination of laziness and hubris. Clearly, there are some differences between the quoted numbers and the unquoted numbers, but Perl will convert between strings and numbers very readily, and you will seldom be able to spot that it is the 'wrong type'.

If there is a big issue, please explain more clearly what the problem is, including sample data, etc.

#!/bin/perl -w
use strict;
use Data::Dumper;

my %credit;

while (<>)
{
        my($passport_no,$bank,$statement) = split / /;
        if (defined $credit{$passport_no}{$bank}{$statement}) {
                $credit{$passport_no}{$bank}{$statement}++;
        } else {
                $credit{$passport_no}{$bank}{$statement} = 1;
        }
}

print Dumper(%credit);

Given the same data file as before, this yields:

$VAR1 = '4126858';
$VAR2 = {
          'Barclays' => {
                          '2948596' => 2,
                          '2948595' => 1,
                          '2948597' => 3
                        },
          'HSBC' => {
                      '2948591' => 1
                    }
        };
$VAR3 = '4126897';
$VAR4 = {
          'HSBC' => {
                      '2948608' => 1,
                      '2948609' => 2
                    }
        };

And this code, which uses the amount (fourth column) that was included in the data:

#!/bin/perl -w
use strict;
use Data::Dumper;

my %credit;

while (<>)
{
        my($passport_no,$bank,$statement,$amount) = split / /;
        $credit{$passport_no}{$bank}{$statement} += $amount
}

print Dumper(%credit);

Yields the output:

$VAR1 = '4126858';
$VAR2 = {
          'Barclays' => {
                          '2948596' => '136.46',
                          '2948595' => '53.23',
                          '2948597' => '190.69'
                        },
          'HSBC' => {
                      '2948591' => '43.23'
                    }
        };
$VAR3 = '4126897';
$VAR4 = {
          'HSBC' => {
                      '2948608' => '13.23',
                      '2948609' => '56.46'
                    }
        };

And, finally, using Data::Dumper::Dumper slightly differently:

#!/bin/perl -w
use strict;
use Data::Dumper;

my %credit;

while (<>)
{
        my($passport_no,$bank,$statement,$amount) = split / /;
        $credit{$passport_no}{$bank}{$statement} += $amount
}

print Dumper(\%credit);

This yields the better output:

$VAR1 = {
          '4126858' => {
                         'Barclays' => {
                                         '2948596' => '136.46',
                                         '2948595' => '53.23',
                                         '2948597' => '190.69'
                                       },
                         'HSBC' => {
                                     '2948591' => '43.23'
                                   }
                       },
          '4126897' => {
                         'HSBC' => {
                                     '2948608' => '13.23',
                                     '2948609' => '56.46'
                                   }
                       }
        };

When you pass '%credit', Perl sends an array of four values - the first is the first key, the second is the first value (structured), the third is the second key, and the last is the second value. When you pass '\%credit', you pass a single reference to the hash, and Dumper recognizes this and treats it all as a single value to be dissected.

Jonathan Leffler
"AFAICS, the only difference between what you got and what you wanted was the absence of some quotes around some of the values" - I think the real issue is the value of 2948597 in $VAR4. Your sample date has multiple instances of the same statement, which the asker's didn't.
Hobo
@Hobo: when I wrote the answer, the question only contained sample output, not the sample data. So, I had to reconstitute the sample data from the sample output. The data provided was then not consistent with the sample output - which doesn't help give good answers.
Jonathan Leffler
+1  A: 

I think your problem is that

 if ($credit{$passport_no}{$bank}) { 
        $credit{$passport_no}{$bank}->{$statement}++;
 } else { 
        $credit{$passport_no}{$bank}->{$statement} = 0;
 }

includes the statement in the key - you need to keep your counter at the passport and bank level (likely in a separate variable).

Hobo
+4  A: 

It's very simply, you should save your auto-increment separated from your indexes.

use strict;
use warnings;
use Data::Dumper;

my ( %counts, %credit );
while (<DATA>) {
    my ( $passport_no, $bank, $statement ) = split / /;
    $credit{$passport_no}{$bank}{$statement} = $counts{$passport_no}{$bank}++;
}

print Dumper( \%credit );

__DATA__
4126897 HSBC 2948608 0
4126897 HSBC 2948609 1
4126897 barclays 2948610 0
4126897 barclays 2948611 1
4126897 barclays 2948612 2
4126897 SBI 2948613 0
4126897 SBI 2948614 1
4126897 SBI 2948615 2
Hynek -Pichi- Vychodil