如何将数组作为列写入CSV

时间:2019-02-06 13:45:58

标签: perl export-to-csv

我有一个数组的哈希。每个哈希键都是一个列名。每个数组都是该列的值。

$myHash{column1} = [value1, value2, ..., valueN];
$myHash{column2} = [value1, value2, ..., valueM];
...

每个数组的长度不同。

我想将其输出为CSV文件,每个数组均为一列。我查看了Text :: CSV,但看不到如何使该结构与该模块一起使用。

谢谢。

3 个答案:

答案 0 :(得分:1)

使用Text::CSV_XS(或Text :: CSV,因为它们共享相同的API)很容易。只需按索引/行号遍历哈希中的数组:

my @columns = sort keys %myHash;
my $rows = scalar @{ $myHash{ $columns[0] }};
my $writer = Text::CSV_XS->new();
open my $fh, '>', 'output.csv' or die "Couldn't write file: $!";

# Output headers
$writer->print($fh, \@columns);

# Output payload
for my $row (0..$rows) {
    $writer->print($fh, [map { $myHash{$_}->[$row] } @columns]);
};

修改问题后,此答案不再完全适用。如果数组的长度不同,则无法为丢失的列添加值。

答案 1 :(得分:0)

您可以分两个步骤进行操作: 1.将数组的哈希值转换为数组的数组 2.编写csv。

我的解决方案允许您使用空白列。如果您在哈希列1,3,5中定义,则列2,4将为空白。

my @twoDarray;
foreach my $row (keys %myHash) {
    my ($colIndex) = $row =~ /(\d+)$/;
    $colIndex--;
    $twoDarray[0][$colIndex] = $row;
    foreach my $rowIndex(0..$#{$myHash{$row}}) {
        $twoDarray[++$rowIndex][$colIndex] = $myHash{$row}->[$rowIndex];
    }
}

my $finalFile = "output.csv";
open my $OUT, ">", $finalFile;
my $csvTo = Text::CSV_XS->new ({ binary => 1, auto_diag => 2, sep_char => ',', allow_whitespace => 1, eol => "\n"});
$csvTo->print ($OUT, $_) for (@twoDarray);
close $OUT;

答案 2 :(得分:0)

如我的评论所述,问题描述不完整。我的解决方案假定:

  1. 哈希键的名称为column1,...,column9column10,依此类推,即,生成的CSV中的列应按嵌入数字进行数字排序。 / li>
  2. 最长的数组定义了生成的CSV中应包含多少行,即未定义的值应映射到空单元格。
#!/usr/bin/perl
use strict;
use warnings;

use List::Util qw(max);
use Text::CSV;

# read in hash-of-arrays
my %hash;
while (<DATA>) {
    chomp;
    my($column, @values) = split(' ');
    $hash{$column} = \@values;
}

# column sort order (using Schwartzian transform)
my @column_order =
    map  { $_->[0] }               # [ "columnN", N ] -> "columnN"
    sort { $a->[1] <=> $b->[1] }   # numerical sort, ascending
    map  { [ /^(column(\d+))$/ ] } # "columnN" -> [ "columnN", N ]
    keys %hash;

# calculate highest array index
my $max_index =
    max
    map { $#{ $_ } }
    values %hash;

# transpose hash-of-arrays and print CSV to STDOUT
my $csv = Text::CSV->new();
$csv->eol("\n");    
$csv->print(\*STDOUT, \@column_order);
for my $index (0..$max_index) {
    my @row =
        map { $hash{$_}->[$index] // '' }
        @column_order;
    $csv->print(\*STDOUT, \@row);
}

exit 0;

__DATA__
column1   1  2  3
column2   4  5  6 7
column3   8  9
column4  10 11 12
column5  13 14 15 16 17 18
column6
column7  19 20 21 22
column8  23
column9  24 25 26
column10 27 28 29 30

使用嵌入式测试数据运行

$ perl dummy.pl
column1,column2,column3,column4,column5,column6,column7,column8,column9,column10
1,4,8,10,13,,19,23,24,27
2,5,9,11,14,,20,,25,28
3,6,,12,15,,21,,26,29
,7,,,16,,22,,,30
,,,,17,,,,,
,,,,18,,,,,