【问题标题】:Transposing CSV data in Perl在 Perl 中转置 CSV 数据
【发布时间】:2013-09-14 21:44:28
【问题描述】:

我是一名 Perl 初学者,目前正在编写一个 Perl 脚本来自动化我们的一些任务。我正在处理的一个脚本涉及从我们的系统中提取性能数据,将其存储在 CSV 文件中并生成 Excel 图表。在处理这个脚本几天后,我设法将提取的数据转换为 CSV,但现在,我很难尝试转置数据!我看过这个帖子(感谢 dalton 的脚本):stackoverflow thread,但我似乎无法在我的情况下应用它。

基本上,我的 CSV 文件每行包含一个每日数据,列是一天中的小时数(24 小时):

29-Aug-2013,3.68,3.63,3.75,3.65,3.65,3.11,3.34,2.74,2.83,2.52,3.19,4.24,3.84,3.61,3.69,2.96,2.76,2.91,3.70,3.82,3.70,3.54,2.54,3.90
30-Aug-2013,3.46,2.97,3.83,3.55,3.41,3.47,3.32,2.81,2.80,2.32,3.17,3.60,3.63,3.83,3.67,2.92,2.34,3.21,3.45,3.51,3.57,3.46,3.52,4.19
31-Aug-2013,3.19,3.50,4.01,3.91,3.71,3.33,3.20,2.95,2.90,2.37,3.07,3.48,2.86,3.29,3.22,2.52,1.83,2.83,3.54,3.49,3.62,3.59,3.54,3.31
01-Sep-2013,2.88,3.16,2.79,2.90,3.78,3.18,3.26,2.84,3.21,2.50,3.35,3.78,3.30,4.04,3.80,3.07,3.23,3.54,3.30,3.43,3.56,3.48,3.60,3.78
02-Sep-2013,3.28,2.92,3.89,3.78,3.54,3.09,3.08,2.79,2.87,2.43,2.70,3.64,3.79,3.88,3.88,3.28,2.90,3.37,3.25,3.60,3.45,3.39,2.84,4.07
03-Sep-2013,3.31,2.54,3.59,3.59,3.50,3.10,2.98,2.63,3.20,2.53,2.92,3.42,3.76,3.07,3.41,2.42,2.12,3.19,3.32,3.08,3.63,3.50,3.71,3.75
04-Sep-2013,3.64,3.48,2.86,3.57,3.68,3.53,3.34,2.89,2.79,2.64,3.30,4.04,4.17,3.70,3.81,2.96,3.41,3.48,3.66,3.05,3.23,3.41,3.15,4.31

现在,我想转置它,以便我将写入新 CSV 文件的结果数据如下所示:

Time,29-Aug-2013,30-Aug-2013,1-Sep-2013,2-Sep-2013,3-Sep-2013,4-Sep-2013
01:00,3.68,3.46,3.19,2.88,3.28,3.31,3.64
02:00,3.63,2.97,3.50,3.16,2.92,2.54,3.48
03:00,3.75,3.83,4.01,2.79,3.89,3.59,2.86
...

现在,我的脚本如下所示:

my @rows = ();
my @transposed = ();

open F1,"D:\\Temp\\perf_data.csv";
while(<F1>) {
    chomp;
    push @rows, split [ /,/ ];
}
#print @rows;

for my $row (@rows) {
  for my $column (0 .. $#{$row}) {
    push(@{$transposed[$column]}, $row->[$column]);
  }
}

for my $new_row (@transposed) {
  for my $new_col (@{$new_row}) {
      print $new_col, ",";
  }
  print "\n";
}

我什至无法从中得到结果!有人可以帮我提供一些关于如何做到这一点的提示吗?提前致谢!

【问题讨论】:

  • 看起来您主要是从stackoverflow.com/q/3249508/725418 复制代码。不过,你犯了一个严重错误。 split [ /,/ ] 应该是 [ split /,/ ]
  • TLP - 是的,这就是我在帖子中感谢海报的原因。我相信我在这里尝试做的是逐行提取我的 CSV 文件并将其用作数组数组。但是,我似乎无法将它放在新数组@rows 中。我会尝试你的建议并让你知道。谢谢!
  • TLP - 就是这样!它现在正在工作!非常感谢您的帮助!
  • 不客气。我会添加一个答案,这样您就不会在历史记录中收到未回答的问题。
  • 顺便说一句:一些基本规则 1) 始终使用 use strict; use warnings; 来启动您的脚本 2) 一旦字段中出现任何重要内容,请使用 Text::CSV 或家人来读写 CSV; 3) 为您的脚本添加输入文件参数,而不是将它们硬编码到您的文件中,这使您的脚本更易于使用和测试

标签: perl csv transpose


【解决方案1】:

你犯了一个简单但严重的错误。

split [ /,/ ] 

应该是

[ split /,/ ]

split 的语法是

split /PATTERN/, EXPR, LIMIT

后两者是可选的。您正在做的是将匿名数组 ref 作为PATTERN 传递,它很可能会被字符串化为ARRAY(0x54d658) 之类的东西。结果是行没有被分割,整行被推到数组上。稍后,这将导致 $row 的取消引用失败并出现错误

Can't use string ("29-Aug-2013,3.68,3.63,3.75,3.65,"...) as an ARRAY ref while "
strict refs" in use at foo.pl line 18, <F1> line 7.

【讨论】:

    【解决方案2】:

    这是我将行数据转换为列的 Perl 程序。 一行以标题名称开头,后跟一个或多个值。 在我的情况下,我需要从标题中删除日期(mm/dd/yyyy),以便标题字段的其余部分在多行中是唯一的。

    sub usage { << "EOF";
    
    Convert rows to columns.
    Remove dates from column headings. 
    
    Usage:
        perl $0
    Example:
       $0 data-to-transpose.txt
    
    Source data:
        header1, row1Value1, row2Value2
        header2, row2Value1
        header3 11/31/2011, row3Value1, row3Value2
    Output:
        header1, header2, header3
        row1Value1, row2Value1, row3Value1
        row1Value2, , row3Value2
    
    EOF
    }
    #
    #-------------------------------------------------------------------------------
    
    use 5.010;
    use strict;
    use warnings;
    
    # use Data::Dumper;
    sub printColumns;
    
    my $inFile = shift or die usage();
    # @ARGV = ('.') unless @ARGV;
    
    my @headers;        # Order list of column headers
    my %data;           # map{colHeader, arrayColSourceData }
    my $colCnt = 0;     # maximum number of columns in source data, header, value1, value2, ....
    my $printColHeaders = 1;
    
    my %hasharray; open (my $fh, "<", $inFile) or die "can't open the $inFile";
    while (<$fh>) {
        chomp;
        my @parts = split /,/; 
    
        if (@parts > 1) {
            # Remove date from heading field
            (my $header = $parts[0]) =~ s/[0-9]+\/[0-9]+\/[0-9]+//;
    
            if (!exists $data{$header}) {
               push @headers, $header;
            }
    
            my $have = $data{$header};
            if (defined $data{$header}) {
                if ($printColHeaders == 1) {
                    $printColHeaders = 0;
                    foreach my $col (@headers) {
                        print "$col,";
                    }
                    print "\n";
                }
    
                printColumns();
    
                foreach my $col (@headers) {
                     $data{$col} = undef;
                }
            } 
    
            $data{$header} = \@parts;
            $colCnt = (@parts > $colCnt) ? @parts : $colCnt;
        }
    } 
    
    printColumns();
    print "\n";
    
    foreach my $col (@headers) {
        print "$col,";
    }
    print "\n";
    
    #### Subs 
    sub printColumns() {
        for my $row (1 .. $colCnt-1) {
            foreach my $colHeader (@headers) {
                my $colData = $data{$colHeader};
                if (defined $colData) {
                    my $len=@$colData;
                    if (defined $colData && $row < @$colData) {
                        print "$colData->[$row], ";
                    } else {
                        print ", ";
                    }
                } else {
                    print ", ";
                }
            }
            print "\n";
        } 
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-08-10
      • 1970-01-01
      • 2013-08-06
      • 2015-07-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多