Как записать массивы в CSV в виде столбцов - PullRequest
0 голосов
/ 06 февраля 2019

У меня есть хэш массивов.Каждый хэш-ключ является именем столбца.Каждый массив - это значения для этого столбца.

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

Каждый массив имеет разную длину.

Я хочу вывести его в виде файла CSV, где каждый массив является столбцом.Я посмотрел на Text :: CSV, но не понимаю, как заставить эту структуру работать с этим модулем.

Спасибо.

Ответы [ 3 ]

0 голосов
/ 06 февраля 2019

Вы можете сделать это в два этапа: 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;
0 голосов
/ 06 февраля 2019

Как указано в моем комментарии, описание проблемы неполное.Мое решение предполагает:

  1. ключи хеш-функции имеют имена column1, ..., column9, column10 и т. Д., Т. Е. Столбцы в сгенерированном CSV должны быть отсортированы в числовом виде повнедренное число.
  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,,,,,
0 голосов
/ 06 февраля 2019

Это легко, используя 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]);
};

После редактирования вопроса этот ответ больше не применяется полностью.Если массивы имеют разную длину, невозможно добавить значения для пропущенных столбцов.

...