10106


出力の5項目目に出力した1項目目＋3項目目が同一の件数をカウントして表示したいです。

各処理の説明。  
input.csvを読み込んで、output.txtを出力する。  
input.csvの2項目からブレイク処理に応じて3項目目と4項目目を作成。

3項目目は、1から始まり2項目目がブレイクすると+1、1項目目がブレイクすると1にリセット。  
ついで、データ連番が10になっても+1カウントします。

4項目目は、1から始まり1項目目が同じなら+1ずつカウントし、ブレイクしたら1にリセット。

入力データ(input.csv)

[code]

    1,A0000001
    1,A0000001
    1,A0000001
    1,B0000001
    1,B0000001
    2,B0000001
    2,B0000002
    3,C0000001
    3,C0000001
    3,C0000001
    3,C0000001
    3,C0000001
    3,C0000001
    3,C0000001
    3,C0000001
    3,C0000001
    3,C0000001
    3,C0000001
    3,C0000001
    
[/code]

現在の出力(output.txt)

[code]

    001,A0000001,0000001,0000001,001
    001,A0000001,0000001,0000002,001
    001,A0000001,0000001,0000003,001
    001,B0000001,0000002,0000004,002
    001,B0000001,0000002,0000005,002
    002,B0000001,0000001,0000001,002
    002,B0000002,0000002,0000002,001
    003,C0000001,0000001,0000001,001
    003,C0000001,0000001,0000002,001
    003,C0000001,0000001,0000003,001
    003,C0000001,0000001,0000004,001
    003,C0000001,0000001,0000005,001
    003,C0000001,0000001,0000006,001
    003,C0000001,0000001,0000007,001
    003,C0000001,0000001,0000008,001
    003,C0000001,0000001,0000009,001
    003,C0000001,0000001,0000010,001
    003,C0000001,0000002,0000011,001
    003,C0000001,0000002,0000012,001
    
[/code]

出したい出力

[code]

    001,A0000001,0000001,0000001,003
    001,A0000001,0000001,0000002,003
    001,A0000001,0000001,0000003,003
    001,B0000001,0000002,0000004,002
    001,B0000001,0000002,0000005,002
    002,B0000001,0000001,0000001,001
    002,B0000002,0000002,0000002,001
    003,C0000001,0000001,0000001,010
    003,C0000001,0000001,0000002,010
    003,C0000001,0000001,0000003,010
    003,C0000001,0000001,0000004,010
    003,C0000001,0000001,0000005,010
    003,C0000001,0000001,0000006,010
    003,C0000001,0000001,0000007,010
    003,C0000001,0000001,0000008,010
    003,C0000001,0000001,0000009,010
    003,C0000001,0000001,0000010,010
    003,C0000001,0000002,0000011,002
    003,C0000001,0000002,0000012,002
    
[/code]

ソースコード

[code]

    use strict;
    use warnings;
    
    # デバックプリント
    my $debug = 0;
    my $debug2 = 0;
    
    # 初期化
    my $num = 0;        #処理区分
    my $card_num = 0;   #カード契約番号
    my $serial_num = 0;     #通数連番
    my $serial_data = 1;    #データ連番
    my $sheets = 1;     #枚数
    my @in1;        #入力データ
    my %hash = ();  #入力データ
    my $line1 = "";
    
    my $sheets_count = 0;
    my $serial_num_count = 0;
    
    
    # キー
    my $inKEY = undef;      #入力キー
    my $cardKEY = undef;    #入力キー２
    my $serialKEY = undef;
    
    # テスト結果
    my $in1_ctr = 0;
    my $out1_ctr = 0;
    
    # ファイルオープン
    open(IN1, "input.csv") or die ":$!";
    open(OUT1, ">output.txt") or die ":$!";
    
    while(my $line1 = <IN1>) {
        chomp($line1);
        @in1 = split(/,/, $line1,-1);
        # キーの設定
        $num = $in1[0];
        $card_num = $in1[1];
    
        # データ入力件数をカウント
        $in1_ctr++;
    
        #処理区分が同じ
        if ($inKEY eq $num) {
            $serial_data++;
            print "\n処理区分同じ\n";
            print "\$sheets_count = $sheets_count\n";
            print "\$num = $num\n";
            print "\$card_num = $card_num\n";
            print "\$serial_num = $serial_num\n";
    
            #処理区分同じのカード番号ブレイク
            if ($cardKEY ne $card_num) {
                $serial_num++;
                $sheets = $sheets_count;
                $sheets_count = 1;
                print "\n処理区分同じのカード番号ブレイク\n";
                print "\$sheets_count = $sheets_count\n";
                print "\$num = $num\n";
                print "\$card_num = $card_num\n";
                print "\$serial_num = $serial_num\n";
            }
    
            #処理区分同じの通数連番同じ
            elsif ( $serialKEY eq $serial_num) {
                $sheets_count++;
                # $sheets = $sheets_count;
                print "\n処理区分同じの通数連番同じ\n";
                print "\$sheets_count = $sheets_count\n";
                print "\$num = $num\n";
                print "\$card_num = $card_num\n";
                print "\$serial_num = $serial_num\n";
            }
    
        }
        #処理区分ブレイク
        elsif ($inKEY ne $num) {
            $serial_data = 1;   
            $serial_num = 0;
            $sheets_count = 1; 
            print "\n処理区分ブレイク\n";
            print "\$sheets_count = $sheets_count\n";
            print "\$num = $num\n";
            print "\$card_num = $card_num\n";
            print "\$serial_num = $serial_num\n";
    
            #処理区分ブレイクのカード番号ブレイク
            if ($cardKEY ne $card_num) {
                $serial_num++;
                $sheets_count = 1;
                $sheets = 1;
                print "\n処理区分ブレイクのカード番号ブレイク\n";
                print "\$sheets_count = $sheets_count\n";
                print "\$num = $num\n";
                print "\$card_num = $card_num\n";
                print "\$serial_num = $serial_num\n";
            }
    
            #処理区分ブレイクのカード契約番号ブレイク
            elsif ($cardKEY eq $card_num) {
                $serial_num = 1;
                $sheets_count = 1;
                print "\n処理区分ブレイクのカード契約番号ブレイク\n";
                print "\$sheets_count = $sheets_count\n";
                print "\$num = $num\n";
                print "\$card_num = $card_num\n";
                print "\$serial_num = $serial_num\n";
            }
    
            #処理区分ブレイクの通数連番同じ
            elsif ( $serialKEY eq $serial_num) {
                $sheets_count++;
                $sheets = $sheets_count;
                print "\n処理区分ブレイクの通数連番同じ\n";
                print "\$sheets_count = $sheets_count\n";
                print "\$num = $num\n";
                print "\$card_num = $card_num\n";
                print "\$serial_num = $serial_num\n";
            }
        }
    
        # データ連番が11以上なら通数連番を+1
        if ($serial_data == 11) {
            $serial_num++;
        }
        &s_out();
    }
    
    close(OUT1);
    close(IN1);
    
    # 結果表示
    printf "入力ファイルの件数：%9d\n", $in1_ctr;
    printf "出力ファイルの件数：%9d\n", $out1_ctr;
    
    # 出力時の処理
    sub s_out {
        $num = $in1[0];
        $card_num = $in1[1];
        $out1_ctr++;
    
        my $out1 = sprintf("%03d,%08s,%07d,%07d,%03d", $num, $card_num, $serial_num, $serial_data, $sheets);
        print OUT1 "$out1\n";
    
        # 出力後のキー
        $inKEY = $in1[0];
        $cardKEY = $in1[1];
        $serialKEY = $sheets_count;
        print "\$inKEY = 出力後：$inKEY\n" if ($debug);
        print "\$cardKEY = 出力後：$cardKEY\n" if ($debug);
        print "\$serialKEY = 出力後：$serialKEY\n" if ($debug);
    }
    
[/code]


CC BY-SA 3.0
2015-05-12T04:13:22.487
10070
2015-05-13T10:46:45.943
2015-05-13T03:18:05.363
9693
9693
question
perl
連番処理でのブレイク処理で


出力の5カラム目は、出力の2カラム目が変更されるまでの個数になるかと思いますので、変更された事を判断して行を戻って値を更新する必要があります。ですので逐次で出力は出来ません。全てメモリに保持する必要があります。

[code]

    use strict;
    use warnings;
    
    open my $fh, '<', 'input.csv' or die "failed to open: $!";
    my $content = do { local $/; <$fh> };
    close $fh;
    
    # CSV データを読み取る
    my @rows;
    my @lines = split "\n", $content;
    for my $line (@lines) {
      push @rows, [(split /,/, $line), 0, 1, 0];
    }
    
    my $prev1 = ""; # 入力1カラム目の前回値
    my $prev2 = ""; # 入力2カラム目の前回値
    my $last5 = 1;  # 出力カラム5
    
    for (my $i = 0; $i < scalar(@rows); $i++) {
      my $row = $rows[$i];
    
      # 1行前の値をコピーしておく
      $row->[2] = $rows[$i-1][2] || 0;
      $row->[3] = $rows[$i-1][3] || 0;
    
      # 出力3カラム目が変更されたかどうかを確認する為に退避しておく
      my $old = $row->[2];
    
      # 入力1カラム目が違う
      if ($prev1 eq $row->[0]) {
        # 出力4カラム目が10を超えるか
        # 入力2カラム目が違う
        # ので出力3カラム目をインクリメント
        if ($row->[3] % 10 == 0 || $prev2 ne $row->[1]) {
          # 出力3カラム目をインクリメント
          $row->[2]++;
        }
    
        # 出力4カラム目をインクリメント
        $row->[3]++;
      } else {
        # リセット
        $row->[3] = 1;
        $row->[2] = 1;
      }
    
      # 出力2カラム目が変更された
      if ($old ne '' && $old ne $row->[2]) {
        # 出力2カラム目が同じであった個数が $last5 に入っているので
        # 行を戻って値が入っていない部分(0)を更新していく
        for (my $j = $i-1; $j >= 0; $j--) {
          last if $rows[$j]->[4] ne 0;
          $rows[$j]->[4] = $last5;
        }
        $last5 = 1;
      } else {
        $last5++;
      }
      $prev1 = $row->[0];
      $prev2 = $row->[1];
    }
    
    # 出力2カラム目が同じであった個数が $last5 に入っているので
    # 行を戻って値が入っていない部分(0)を更新していく
    for (my $j = scalar(@rows)-1; $j >= 0; $j--) {
      last if $rows[$j]->[4] ne 0;
      $rows[$j]->[4] = $last5;
    }
    
    # データを表示
    for my $row (@rows) {
      print sprintf("%03d,%08s,%07d,%07d,%03d\n",
        $row->[0], $row->[1], $row->[2], $row->[3], $row->[4]);
    }
    
[/code]


CC BY-SA 3.0
2015-05-13T05:21:37.283
10106
2015-05-13T10:46:45.943
2015-05-13T10:46:45.943
440
440
10070
answer