填充哈希perl的哈希值

时间:2012-11-28 12:12:09

标签: perl hash

我有以下哈希散列:

my %MacroA = ('Category' => {}, 'Item' => {}, 'Description' => {}, 'Score' => {});

我想要的是遍历文件,然后将新元素添加到不同的哈希值。让我们说该行包含“布局”我想在每次看到它时将其存储在“类别”中

我所做的是:

while (my $line = <$file>) {                                        

if ($line =~ /\b(layout)\b,/) { 
foreach my $categories (keys $MacroA{'Category'}) {
    $MacroA{Category} = $1;
}
}

5 个答案:

答案 0 :(得分:3)

您的问题非常容易引起混淆,但您的问题似乎是因为您在引用而不是哈希上执行keys。较新的perls确实支持这一点,但你可能使用旧版本。

在您的示例中$MacroA{'Category'}返回哈希引用,而不是哈希。您使用'Category' => {}初始化哈希,{}是对空匿名哈希的引用。

要将哈希引用转换为哈希,请使用%{ ... }表示法;在这种情况下,你要写keys %{ $MacroA{'Category'} }。是的,这很难看,这就是为什么Perl被改为支持引用的keys

但请注意,您的下一行是$MacroA{Category} = $1;,它将使用$1中的任何内容替换引用,可能是字符串"layout"。这不是一个引用,所以下一次while循环时,你的脚本将会完成。你可能想要做一个多级哈希,比如$MacroA{Category}{$1} = $file或类似的东西,这取决于你想要在哈希中建立什么数据,但是你真正想要实现的是什么。另一个建议阵列散列的答案可能就是你想要的。在这种情况下,如果使用较旧的perl,则表示法@{ ... }会将数组引用转换为可与push一起使用的数组。

答案 1 :(得分:2)

看起来你正试图在这里做一些命名列的事情。这是 非常直接,如果你知道怎么做。

从你的评论到彼得(“[我]想要存储”布局“各自 行至'描述'“)这是该代码允许您执行的操作:存储它。

因为我看到哈希的主要情况是记录本身,这是唯一的哈希 这个演示使用。它将它们存储在一个数组中。我真的不明白你的意思 想从你的例子中索引它们。你似乎对你有点困惑 想要处理它们。当然,处理每一行都没有用 其中包含'layout',然后将其存储为“类别”字段。

use strict;
use warnings;

my @columns = qw<field1 field2 field3 field4>;
my @list;
my $fh = \*::DATA;
my $header = <$fh>;
if ( substr( $header, 0, 1 ) eq '#' ) {
    ( $header ) = $header =~ m/#(.*)/;
    $header =~ s/\s+$//; 
    @columns = split /,\s*/, $header;
}
else { 
    seek( $fh, 0, 0 ); # go back
}

# optional statement to capitalize field names
@columns = map { ucfirst } @columns;

while ( my $line = <$fh> ) { 
    next unless $line =~ m/^\s*layout\b/;
    $line =~ s/\s*$//;
    # store fields by hash slice in the tip of the array
    @{ $list[@list] }{ @columns } = split /,\s*/, $line;
}

__DATA__
#category, item, description, score 
layout,f.4,Macro placement clearance,pass 
layout,f.14,No area congestion,pass 
layout,f.17,placement collar diode,fail 
layout,f.18,placement collar buffer,pass 
layout,f.26,tie connection,fail 
layout,f.28,CTS allowed cell,fail 
layout,f.29,CTS allowed layed,pass 
layout,f.31,Clock De-cap cell,fail 
layout,f.33,Clock non default rule,fail

虽然这不是你想要的一切,但是将记录复制到 一个数组是简单“处理它”的模型,我们可以做这样的事情 相反:

my %by_item;
while ( my $line = <$fh> ) { 
    next unless $line =~ m/^\s*layout\b/;
    $line =~ s/\s*$//;
    my %h;
    @h{ @columns } = split /,\s*/, $line;
    $by_item{ $h{Item} } = \%h;
    ### OR 
    # push @{ $by_item{ $h{Item} } }, %h;
}

你也可以这样做:

my %by_field;
...
$by_field{Item}{ $h{Item} }               
    = $by_field{Description}{ $h{Description} } 
    = \%h
    ;

答案 2 :(得分:1)

我认为你需要一个数组哈希:

my %MacroA = ('Category' => [], 'Item' => [], 'Description' => [], 'Score' => []);

while (my $line = <$file>) {                                        

if ($line =~ /\b(layout)\b,/) { 
foreach my $categories (keys $MacroA{'Category'}) {
    push $MacroA{Category}, $1;
}
}

答案 3 :(得分:1)

你的问题令人困惑。只需在“类别”键中添加“布局”很简单,不涉及循环:

while (my $line = <$file>) {                                        
    if ($line =~ /\blayout\b,/) { 
        $MacroA{Category} = 'layout';
    }
}

答案 4 :(得分:1)

下面是一个完整的程序,分为不同的块。要运行它,请将答案复制并粘贴到名为populate的文件中,但要删除评论部分,例如此段落。

几乎所有的Perl程序(特别是在你还是初学者的时候)都应该以

开头
#! /usr/bin/env perl

use strict;
use warnings;

第一行告诉系统如何执行程序。启用strictwarnings pragmata将帮助您避免常见错误,并帮助您解释在您看到令人惊讶的行为时您的计划正在执行的操作。

根据您的问题,您需要的数据结构是一个哈希数组。数组的每个“行”或元素将对应于输入文件中的一行,其格式为

# { Category => '...', Item => '...', Description => '...', Score => '...' }

程序还将从输入中读取列名。

代码使用Perl的“菱形运算符”来读取每行输入。如果存在,chomp会删除尾随换行符。

如果该行告诉我们标题名称(即。,它以#开头),我们将每个字段存储在@columns中。 ucfirst位可能不熟悉: pper c 评论字符串的第一个字符。由于有多个列名称,我们使用mapucfirst应用于每个。

否则,该行代表数据行。我们将split行划分为以逗号分隔的字段,并将它们加载到新的哈希中。 push行将引用(使用散列前的反斜杠创建)添加到@MacroA的末尾。

my @MacroA;
my @columns;
while (<>) {
  chomp;

  if (s/^#//) {                               # / fix Stack Overflow coloring
    @columns = map ucfirst, split /\s*,\s*/;  # / ditto
  }
  else {
    my %row;
    @row{@columns} = split /,/;
    push @MacroA, \%row;
  }
}

请注意,上面的拆分是naïaut; ve。要处理常规CSV输入,请使用CSV modules on CPAN之一。

Data::Dumper模块对于快速打印复杂数据结构的内容非常有用。将其粘贴在调试工具包中。

use Data::Dumper;
$Data::Dumper::Indent = $Data::Dumper::Terse = 1;
print Dumper \@MacroA;

__END__

给定文件input,其内容低于

#category, item, description, score
layout,f.4,Macro placement clearance,pass
layout,f.14,No area congestion,pass
layout,f.17,placement collar diode,fail
layout,f.18,placement collar buffer,pass
layout,f.26,tie connection,fail
layout,f.28,CTS allowed cell,fail
layout,f.29,CTS allowed layed,pass
layout,f.31,Clock De-cap cell,fail
layout,f.33,Clock non default rule,fail

示例运行如下。

$ perl populate input
[
  {
    'Score' => 'pass',
    'Item' => 'f.4',
    'Description' => 'Macro placement clearance',
    'Category' => 'layout'
  },
  {
    'Score' => 'pass',
    'Item' => 'f.14',
    'Description' => 'No area congestion',
    'Category' => 'layout'
  },
  {
    'Score' => 'fail',
    'Item' => 'f.17',
    'Description' => 'placement collar diode',
    'Category' => 'layout'
  },
  {
    'Score' => 'pass',
    'Item' => 'f.18',
    'Description' => 'placement collar buffer',
    'Category' => 'layout'
  },
  {
    'Score' => 'fail',
    'Item' => 'f.26',
    'Description' => 'tie connection',
    'Category' => 'layout'
  },
  {
    'Score' => 'fail',
    'Item' => 'f.28',
    'Description' => 'CTS allowed cell',
    'Category' => 'layout'
  },
  {
    'Score' => 'pass',
    'Item' => 'f.29',
    'Description' => 'CTS allowed layed',
    'Category' => 'layout'
  },
  {
    'Score' => 'fail',
    'Item' => 'f.31',
    'Description' => 'Clock De-cap cell',
    'Category' => 'layout'
  },
  {
    'Score' => 'fail',
    'Item' => 'f.33',
    'Description' => 'Clock non default rule',
    'Category' => 'layout'
  }
]