2011-12-20 169 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