【问题标题】:Perl - need to store the column values into hashPerl - 需要将列值存储到哈希中
【发布时间】:2015-03-18 10:31:47
【问题描述】:

我想在 Perl 中创建一个以列标题作为散列键、列值作为散列值的散列。

例如,如果我的 csv 文件有以下数据:

A,B,C,D,E 
1,2,3,4,5
6,7,8,9,10
11,12,13,14,15 ...

我想创建一个哈希如下:

A=> 1,6,11
B=>2,7,12
c=>3,8,13 ...

因此,只需使用标题名称,我就可以使用该列值。 PERL 中有没有办法做到这一点?请帮帮我。

我能够使用以下脚本将所需的列值存储为数组

use strict;
use warnings;

open( IN, "sample.csv" ) or die("Unable to open file");
my $wanted_column = "A";
my @cells;
my @colvalues;

my $header       = <IN>;
my @column_names = split( ",", $header );
my $extract_col  = 0;

for my $header_line (@column_names) {
    last if $header_line =~ m/$wanted_column/;
    $extract_col++;
}
while ( my $row = <IN> ) {
    last unless $row =~ /\S/;
    chomp $row;
    @cells = split( ",", $row );
    push( @colvalues, $cells[$extract_col] );
}
my $sizeofarray = scalar @colvalues;
print "Size of the coulmn= $sizeofarray";

但我想对我的所有专栏都这样做。我猜数组哈希将是最好的解决方案,但我不知道如何实现它。

【问题讨论】:

  • 是的,有。到目前为止,您尝试过什么?
  • 另外:您确定要标题 -> 列吗?因为您给出的示例,您已经将标题映射到行。
  • 抱歉,我编辑了问题。我想要列的标题。感谢您强调它。

标签: perl hash


【解决方案1】:

Text::CSV 是处理这类事情的有用帮助模块。

use strict;
use warnings;

use Text::CSV;
use Data::Dumper;

my %combined;
open( my $input, "<", "sample.csv" ) or die("Unable to open file");
my $csv = Text::CSV->new( { binary => 1 } );
my @headers = @{ $csv->getline($input) };

while ( my $row = $csv->getline($input) ) {
    for my $header (@headers) {
        push( @{ $combined{$header} }, shift(@$row) );
    }

}
print Dumper \%combined;

由于您在没有模块的情况下请求 - 您可以使用split,但您需要牢记这些限制。 CSV 格式允许逗号嵌套在引号中。 split 不会很好地处理这种情况。

use strict;
use warnings;

use Data::Dumper;

my %combined;
open( my $input, "<", "sample.csv" ) or die("Unable to open file");
my $line = <$input>;
chomp ( $line );
my @headers = split( ',', $line );

while (<$input>) {
    chomp;
    my @row = split(',');
    for my $header (@headers) {
        push( @{ $combined{$header} }, shift(@row) );
    }

}
print Dumper \%combined;

注意:这两种方法都会有效地忽略任何没有标题的额外列。 (并且会被重复的列名弄糊涂)。

【讨论】:

  • 有什么办法不使用任何模块?我应该在不使用模块的情况下做到这一点。
  • 是的。您可以在, 上使用split。请记住,CSV 允许引号内的逗号之类的内容,split 无法处理。用另一个例子编辑。但是如果可以的话,我会敦促你使用前者,它不太可能在以后打破。
  • 这就是我需要的。谢谢。
  • 请注意,以上将忽略任何没有标题的额外列。
【解决方案2】:

使用for 循环的另一种解决方案:

use strict;
use warnings;

my %data; 
my @columns; 

open (my $fh, "<", "file.csv") or die "Can't open the file : ";

while (<$fh>)
{
    chomp;
    my @list=split(',', $_);
    for (my $i=0; $i<=$#list; $i++)
    {
        if ($.==1)  # collect the columns, if its first line.
        {
            $columns[$i]=$list[$i];
        }
        else        #collect the data, if its not the first line. 
        {
            push @{$data{$columns[$i]}}, $list[$i];
        }
    }
}
foreach (@columns)
{
    local $"="\,";
    print "$_=>@{$data{$_}}\n";
}

输出将是这样的:

A=>1,6,11
B=>2,7,12
C=>3,8,13
D=>4,9,14
E=>5,10,15

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-02-01
    • 2016-06-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-16
    • 1970-01-01
    相关资源
    最近更新 更多