2011-12-20 59 views
4

我已經在Perl中讀取過文件,但是當CSV文件具有我需要在不同行上所需的值時。我想我必須創建一個混合使用哈希鍵的數組,但我在這裏不在我的聯盟中。在Perl中讀取CSV文件

基本上,我的CSV文件包含以下列:branch, job, timePeriod, periodType, day1Value, day2Value, day3Value, day4Value, day4Value, day6Valueday7Value

day *值分別表示每週的每一天的periodType的值。

例如 -

East,Banker,9AM-12PM,Overtime,4.25,0,0,1.25,1.5,1.5,0,0 
West,Electrician,12PM-5PM,Regular,4.25,0,0,-1.25,-1.5,-1.5,0,0 
North,Janitor,5PM-12AM,Variance,-4.25,0,0,-1.25,-1.5,-1.5,0,0 
South,Manager,12A-9AM,Overtime,77.75,14.75,10,10,10,10,10,

等等

我需要輸出的文件需要這個數據和密鑰關閉分支,工作,TIMEPERIOD,和一天。我的輸出將列出每個特定日期的每個periodType值,而不是所有七個periodType值。

例如 -

South,Manager,12A-9AM,77.75,14.75,16

在上面的行,最後3個值代表三個periodTypes(超時,定期,和方差)day1Values

正如你所看到的,我的問題是我不知道如何將數據加載到內存中,這種方式允許我從不同的行中獲取數據併成功輸出。我以前只是從單線上解析出來的。

回答

14

除非你喜歡疼痛,否則使用Text::CSV及其親屬Text::CSV_XSText::CSV_PP

但是,這可能是這個問題的更容易的部分。一旦閱讀並驗證了該行是完整的,則需要將相關信息添加到正確鍵入的散列。你可能也必須非常熟悉參考文獻。

您可以創建分支鍵入的散列%BranchData。該散列的每個元素都是對按作業鍵入的散列的引用;並且其中的每個元素都是對由timePeriod鍵入的散列的引用,並且其中的每個元素都將引用按天數鍵入的數組(使用索引1..7;它稍微分配空間,但獲得它是正確的更大;不要混淆$[雖然!)。並且數組中的每個元素都將是對由三個句點類型鍵入的散列的引用。哎喲!

如果一切運作良好,一個典型的分配可能是這樣的:

$BranchData{$row{branch}}->{$row{job}}->{$row{period}}->[1]->{$row{p_type}} += 
    $row{day1}; 

你會迭代元素1..7和「DAY1」 ..「第7天」;對於那裏的設計工作有一些清理。

你不得不擔心正確地初始化東西(或者你沒有 - Perl會爲你做)。我假設該行作爲直接散列(而不是散列引用)返回,並帶有分支,作業,句點,句點類型(p_type)和每天('day1',..'day7')的鍵。 。

如果您事先知道需要哪一天,您可以避免累積所有日子,但它可以使得更一般的報告更簡單地隨時讀取和累積所有數據,然後只需打印處理任何子集的整個數據需要處理。


這是足夠有趣的問題,我已經黑了這個代碼。我懷疑它是否是最佳的,但它確實有效。

#!/usr/bin/env perl 
# 
# SO 8570488 

use strict; 
use warnings; 
use Text::CSV; 
use Data::Dumper; 
use constant debug => 0; 

my $file = "input.csv"; 
my $csv = Text::CSV->new({ binary => 1, eol => $/ }) 
        or die "Cannot use CSV: ".Text::CSV->error_diag(); 
my @headings = qw(branch job period p_type day1 day2 day3 day4 day5 day6 day7); 
my @days  = qw(day0 day1 day2 day3 day4 day5 day6 day7); 
my %BranchData; 

open my $in, '<', $file or die "Unable to open $file for reading ($!)"; 

$csv->column_names(@headings); 
while (my $row = $csv->getline_hr($in)) 
{ 
    print Dumper($row) if debug; 
    my %r = %$row; # Not for efficiency; for notational compactness 
    $BranchData{$r{branch}} = { } if !defined $BranchData{$r{branch}}; 
    my $branch = $BranchData{$r{branch}}; 
    $branch->{$r{job}} = { } if !defined $branch->{$r{job}}; 
    my $job = $branch->{$r{job}}; 
    $job->{$r{period}} = [ ] if !defined $job->{$r{period}}; 
    my $period = $job->{$r{period}}; 
    for my $day (1..7) 
    { 
     # Assume that Overtime, Regular and Variance are the only types 
     # Otherwise, you need yet another level of checking whether elements exist... 
     $period->[$day] = { Overtime => 0, Regular => 0, Variance => 0} if !defined $period->[$day]; 
     $period->[$day]->{$r{p_type}} += $r{$days[$day]}; 
    } 
} 

print Dumper(\%BranchData); 

鑑於你的樣本數據,從這個輸出是:

$VAR1 = { 
    'West' => { 
     'Electrician' => { 
      '12PM-5PM' => [ 
       undef, 
       { 
        'Regular' => '4.25', 
        'Overtime' => 0, 
        'Variance' => 0 
       }, 
       { 
        'Regular' => 0, 
        'Overtime' => 0, 
        'Variance' => 0 
       }, 
       { 
        'Regular' => 0, 
        'Overtime' => 0, 
        'Variance' => 0 
       }, 
       { 
        'Regular' => '-1.25', 
        'Overtime' => 0, 
        'Variance' => 0 
       }, 
       { 
        'Regular' => '-1.5', 
        'Overtime' => 0, 
        'Variance' => 0 
       }, 
       { 
        'Regular' => '-1.5', 
        'Overtime' => 0, 
        'Variance' => 0 
       }, 
       { 
        'Regular' => 0, 
        'Overtime' => 0, 
        'Variance' => 0 
       } 
      ] 
     } 
    }, 
    'South' => { 
     'Manager' => { 
      '12A-9AM' => [ 
       undef, 
       { 
        'Regular' => 0, 
        'Overtime' => '77.75', 
        'Variance' => 0 
       }, 
       { 
        'Regular' => 0, 
        'Overtime' => '14.75', 
        'Variance' => 0 
       }, 
       { 
        'Regular' => 0, 
        'Overtime' => 10, 
        'Variance' => 0 
       }, 
       { 
        'Regular' => 0, 
        'Overtime' => 10, 
        'Variance' => 0 
       }, 
       { 
        'Regular' => 0, 
        'Overtime' => 10, 
        'Variance' => 0 
       }, 
       { 
        'Regular' => 0, 
        'Overtime' => 10, 
        'Variance' => 0 
       }, 
       { 
        'Regular' => 0, 
        'Overtime' => 10, 
        'Variance' => 0 
       } 
      ] 
     } 
    }, 
    'North' => { 
     'Janitor' => { 
      '5PM-12AM' => [ 
       undef, 
       { 
        'Regular' => 0, 
        'Overtime' => 0, 
        'Variance' => '-4.25' 
       }, 
       { 
        'Regular' => 0, 
        'Overtime' => 0, 
        'Variance' => 0 
       }, 
       { 
        'Regular' => 0, 
        'Overtime' => 0, 
        'Variance' => 0 
       }, 
       { 
        'Regular' => 0, 
        'Overtime' => 0, 
        'Variance' => '-1.25' 
       }, 
       { 
        'Regular' => 0, 
        'Overtime' => 0, 
        'Variance' => '-1.5' 
       }, 
       { 
        'Regular' => 0, 
        'Overtime' => 0, 
        'Variance' => '-1.5' 
       }, 
       { 
        'Regular' => 0, 
        'Overtime' => 0, 
        'Variance' => 0 
       } 
      ] 
     } 
    }, 
    'East' => { 
     'Banker' => { 
      '9AM-12PM' => [ 
       undef, 
       { 
        'Regular' => 0, 
        'Overtime' => '4.25', 
        'Variance' => 0 
       }, 
       { 
        'Regular' => 0, 
        'Overtime' => 0, 
        'Variance' => 0 
       }, 
       { 
        'Regular' => 0, 
        'Overtime' => 0, 
        'Variance' => 0 
       }, 
       { 
        'Regular' => 0, 
        'Overtime' => '1.25', 
        'Variance' => 0 
       }, 
       { 
        'Regular' => 0, 
        'Overtime' => '1.5', 
        'Variance' => 0 
       }, 
       { 
        'Regular' => 0, 
        'Overtime' => '1.5', 
        'Variance' => 0 
       }, 
       { 
        'Regular' => 0, 
        'Overtime' => 0, 
        'Variance' => 0 
       } 
      ] 
     } 
    } 
}; 

有樂趣從這裏走了!

+0

另一個值得考慮的模塊是'Text :: CSV :: Encoded',我用它來處理UTF-8。 – reinierpost 2011-12-20 09:34:12

+0

我相信這段代碼可以滿足我的需求!我只需要以下列格式輸出到另一個CSV文件:
South,Manager,12A-9AM,77.75,14.75,16
在上面的行中,最後3個值表示三種periodTypes(加班,常規和差異)day1Values。 – user1107055 2011-12-20 17:06:08

4

我沒有第一手經驗,但可以使用DBD::CSV,然後傳遞所需的相對簡​​單的SQL查詢來計算所需的聚合。

如果你堅持這樣做了艱辛的道路,但是,可以遍歷和哈希參考以下哈希收集你的數據:

(
    "branch1,job1,timeperiod1"=> 
    { 
     "overtime"=>"overtimeday1value1", 
     "regular"=>"regulartimeday1value1", 
     "variance"=>"variancetimeday1value1" 
    }, 
    "branch2,job2,timeperiod2"=> 
    { 
     "overtime"=>"overtimeday1value2", 
     "regular"=>"regulartimeday1value2", 
     "variance"=>"variancetimeday1value2" 
    }, 
    #etc 
); 

,然後就遍歷相應的按鍵。然而,這種方法確實依賴於密鑰的一致格式(例如,"East,Banker,9AM-12PM""East, Banker, 9AM-12PM"不一樣),所以在製作上述散列的同時,您必須檢查一致的格式(並強制執行)。

+0

對 - 我希望這樣做,所以值可能會改變,它不會破壞程序AKA不硬代碼。 – user1107055 2011-12-20 03:59:58

+0

@ user1107055 - 我想你誤解了我的意思:如果你想這麼做很難,你必須逐行閱讀你的文件並創建上面的哈希引用的哈希。因此,如果您在腳本中執行此操作,請更改文件,然後再次運行腳本,您將得到不同的散列(以及不同的輸出)。 – 2011-12-20 04:01:25

+1

我已經使用過'DBD :: CSV'(實際上我主要使用一個簡單的包裝腳本'csvsql',它允許我在CSV文件上運行任意的SQL查詢),我可以確認它的用處。 – reinierpost 2011-12-20 09:24:16