populate hash of hashes perl



我有以下散列:

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

我想要的是循环浏览一个文件,然后在不同的散列中添加新元素。假设这行包含"布局",我想每次看到时都将其存储在"类别"中

我所做的是:

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

您的问题被问得很困惑,但您的问题似乎是因为您对引用而不是哈希执行keys。较新的perl确实支持此功能,但您可能使用的是较旧的版本。

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

要将散列引用转换为散列,可以使用%{ ... }表示法;在这种情况下,您将编写keys %{ $MacroA{'Category'} }。是的,这很难看,这就是为什么Perl在引用中被更改为支持keys的原因。

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

在这里,您似乎正在尝试做一种命名列的事情。这是非常直接,如果你知道怎么做的话。

从你的评论到Peter("[我]想存储每个人的"布局"行到"描述")这就是这个代码允许你做的:存储它。

因为我看到的哈希的主要情况是记录本身,这是唯一的哈希这个演示使用。它将它们存储在一个数组中。我真的不明白你是怎么想的想从你的例子中对它们进行索引。你似乎有点困惑想要处理它们。当然,用'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*layoutb/;
$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*layoutb/;
$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
;

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

几乎所有Perl程序(尤其是当您还是初学者时)都应该从开始

#! /usr/bin/env perl
use strict;
use warnings;

第一行告诉系统如何执行程序。启用strictwarnings杂注将有助于避免常见错误,并有助于解释程序在出现意外行为时所做的操作。

根据你的问题,你想要的数据结构是一个散列数组。数组的每个"行"或元素将对应于输入文件中的一行,并具有形式

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

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

该代码使用Perl的"菱形运算符"来读取每一行输入。chomp删除尾部换行符(如果存在)。

如果行告诉我们标题名称(,它从#开始),我们将每个字段存储在@columns中。ucfirst位可能不熟悉:它upperc是字符串的第一个字符。因为有几个列名,所以我们使用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&iumlaut;ve。要处理一般CSV输入,请使用CPAN上的CSV模块之一。

Data::Dumper模块可用于快速打印复杂数据结构的内容。把它放在调试工具包里。

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

给定内容低于的文件input

#category,item,description,score布局,f.4,宏放置间隙,通道布局,f.14,无区域拥堵,通行布局,f.17,放置套环二极管,故障布局,f.18,放置轴环缓冲,通道布局,f.26,连接,故障布局,f.28,CTS允许的小区,失败布局,f.29,CTS允许分层,通过布局,f.31,时钟去帽单元,失败layout,f.33,Clock非默认规则,fail

下面是一个示例运行。

$perl填充输入[{"得分"=>"通过",'项目'=>'f.4',"说明"=>"宏放置间隙","类别"=>"布局"},{"得分"=>"通过",'项目'=>'f.14','描述'=>'无区域拥堵',"类别"=>"布局"},{"得分"=>"失败",'项目'=>'f.17',"说明"=>"放置套环二极管","类别"=>"布局"},{"得分"=>"通过",'项目'=>'f.18',"描述"=>"放置项圈缓冲区","类别"=>"布局"},{"得分"=>"失败",'项目'=>'f.26',"描述"=>"连接","类别"=>"布局"},{"得分"=>"失败",'项目'=>'f.28','描述'=>'允许CTS的小区',"类别"=>"布局"},{"得分"=>"通过",'项目'=>'f.29','描述'=>'允许CTS分层',"类别"=>"布局"},{"得分"=>"失败",'项目'=>'f.31','描述'=>'时钟去帽单元',"类别"=>"布局"},{"得分"=>"失败",'项目'=>'f.33','描述'=>'时钟非默认规则',"类别"=>"布局"}]

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

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;
}
}

您的问题令人困惑。只需在Category键中添加"layout"很简单,不涉及循环:

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

最新更新