在哈希散列中维护顺序,并输出为.csv

时间:2016-01-29 07:13:22

标签: perl csv hash

这是我的代码:

my %hash = (
    '2564' => {
                'st_responsible' => 'mname1',
                'critical' => '',
                'last_modified_by' => 'teamname1',
                'transstatus' => '',
                'rt_res' => 'pname1'
                },
    '2487' => {
                'st_responsible' => 'mname2',
                'critical' => '',
                'last_modified_by' => 'teamname2',
                'transstatus' => '',
                'rt_res' => ''
                }
);

print "xnum,st_responsible,critical,last_modified_by,transstatus,rt_res\n";
foreach my $x_number (sort keys %hash)
{
    print "$x_number";
    foreach my $element (keys %{$hash{$x_number}})
    {
        print ",$hash{$x_number}{$element}";
    }
    print "\n";
}

预期输出

xnum,st_responsible,critical,last_modified_by,transstatus,rt_res
2487,mname2,,teamname2,,
2564,mname1,,teamname1,,pname1

实际输出

xnum,st_responsible,critical,last_modified_by,transstatus,rt_res
2487,mname2,,,teamname2,
2564,mname1,,,teamname1,pname1

请帮助我告诉我如何保留此数据结构的顺序,然后将其写入CSV文件。

3 个答案:

答案 0 :(得分:1)

Perl不保证哈希中项目的顺序,这是问题的根本原因。即使两个具有相同键的不同哈希也可以具有不同的键顺序。它可能也因平台和架构以及perl版本而异。

您需要使用要按正确顺序打印的键列表定义另一个数组。

my @keys = qw(st_responsible critical last_modified_by transstatus rt_res);
foreach my $element (@keys) {
    ... print the value
}

编辑:当您尝试编写CSV文件时,请考虑使用Text::CSV来处理特殊字符,更正格式以及类似的内容。

答案 1 :(得分:1)

我建议为此,你最好用slice来做这件事,这是一种从特定顺序的哈希中提取值列表的方法吗?

#configure field order
my @order = qw ( st_responsible critical last_modified_by transstatus rt_res );

#print header row 
print join (",", "xnum", @order ),"\n"; 
#iterate the rows
foreach my $key ( sort keys %hash ) { 
   #extract hash slice and join it with commas
   print join ( ",", $key, @{$hash{$key}}{@order} ),"\n";
} 

这给出了:

xnum,st_responsible,critical,last_modified_by,transstatus,rt_res
2487,mname2,,teamname2,,
2564,mname1,,teamname1,,pname1

您可以考虑使用Text::CSV - 但我建议在这种情况下它过度使用,最好在有引号和引用字段分隔符时使用。 (而你没有)。

如果您不仅要处理空键,还要处理缺失的键,则可以使用map

my @order = qw ( st_responsible critical last_modified_by 
                 transstatus missing rt_res extra_field_here );
print join (",", "xnum", @order ),"\n"; 
foreach my $key ( sort keys %hash ) { 
   print join ( ",", $key, map { $_ // '' } @{$hash{$key}}{@order} ),"\n";
} 

(否则你会得到一个关于undef值的警告)。

答案 2 :(得分:0)

可能有一种更为明智的方法可以实现这一目标,但请试一试:

use warnings;
use strict; 

open my $csv_out, '>', 'out.csv' or die $!;

my @keys = qw(2487 2564);
my @vals = qw(st_responsible critical last_modified_by transstatus rt_res);


print $csv_out "xnum,st_responsible,critical,last_modified_by,transstatus,rt_res\n";

for my $key (@keys){
    print $csv_out "$key,";
        for my $vals (@vals){
            $vals eq $vals[-1] ? print $csv_out "$hash{$key}{$vals}\n" : print $csv_out "$hash{$key}{$vals},";
        }
}

这将以逗号分隔的值打印到csv文件out.csv,保持原始顺序(通过迭代数组)。如果它是最后一个值,它将打印换行符。

--- OUTPUT ---

xnum,st_responsible,critical,last_modified_by,transstatus,rt_res
2487,mname2,,teamname2,,
2564,mname1,,teamname1,,pname1