Perl:从复杂散列将输出格式化为表格格式
我有一个如下的结构Perl:从复杂散列将输出格式化为表格格式,perl,formatting,Perl,Formatting,我有一个如下的结构 my %hash = ( 'P' => { '4' => [ '1/4/1 2', '1/4/1 3' ], '2' => [ '1/2/1 1'
my %hash = (
'P' => {
'4' => [
'1/4/1 2',
'1/4/1 3'
],
'2' => [
'1/2/1 1',
'1/2/5 4'
]
},
'Q' => {
'4' => [
'1/4/1 3'
],
'3' => [
'1/3/1 1'
],
'5' => [
'1/5/1 1'
]
},
);
我想把它格式化成这样
Node 2 3 4 5
P 1/2/1 1 1/4/1 2
P 1/2/5 4 1/4/1 3
Q 1/3/1 1 1/4/1 3 1/5/1 1
我目前正在努力。最后,我需要把它放到excel中。我想像这样的东西可能需要一些调整
my %seen;
my @headers = sort { $a <=> $b } grep {!$seen{$_}++} map{ keys %{$hash{$_}} }keys %hash;
print "node", ' ' x 30, join(" " x 10, @headers),"\n";
foreach my $node (keys %hash) {
my @values;
foreach my $num (keys %{$hash{$node}}) {
foreach my $klm (@{$hash{$node}{$num}}) {
push (@values,$klm);
}
}
foreach my $i (0 .. $#values) {
print "$node $values[$i]\n";
}
}
my%seed;
my@headers=sort{$a$b}grep{!$seen{$}++}map{keys%{$hash{$}}}keys%hash;
打印“节点”,“x 30,联接”(“x 10,@headers)”,“\n”;
foreach my$节点(键%hash){
我的价值观;
foreach my$num(键%{$hash{$node}}){
foreach my$klm(@{$hash{$node}{$num}){
推送(@值,$klm);
}
}
foreach我的$i(0..$#值){
打印“$node$values[$i]\n”;
}
}
欢迎进一步建议。为什么不试试:
my %seen;
my @headers = sort { $a <=> $b } grep {!$seen{$_}++} map{ keys %{$hash{$_}} }keys %hash;
printf("%-25s", "node");
foreach my $node (@headers)
{
printf("%-25s", $node);
}
print "\n";
foreach my $node (keys %hash) {
printf "%-25s", $node;
foreach my $num (@headers)
{
if(defined($hash{$node}{$num}))
{
my $string = join(" ", @{$hash{$node}{$num}});
printf "%-25s", $string ;
}
else
{
printf "%-25s", " " ;
}
}
print "\n";
}
my%seed;
my@headers=sort{$a$b}grep{!$seen{$}++}map{keys%{$hash{$}}}keys%hash;
printf(“%-25s”,“节点”);
foreach my$节点(@headers)
{
printf(“%-25s”,$node);
}
打印“\n”;
foreach my$节点(键%hash){
printf“%-25s”,$node;
foreach my$num(@headers)
{
if(已定义($hash{$node}{$num}))
{
my$string=join(“,@{$hash{$node}{$num});
printf“%-25s”,$string;
}
其他的
{
printf“%-25s”,“”;
}
}
打印“\n”;
}
@辛巴布谢谢你的评论
这个版本已经过调试和测试我直接使用Excel文件来完成,因为我认为处理行、列和目标单个字段比直接处理输出更容易
use strict;
use warnings 'all';
use Excel::Writer::XLSX;
my %hash = (
'P' => {
'4' => [ '1/4/1 2', '1/4/1 3' ],
'2' => [ '1/2/1 1', '1/2/5 4' ]
},
'Q' => {
'4' => ['1/4/1 3'],
'3' => ['1/3/1 1'],
'5' => ['1/5/1 1']
},
);
my %seen;
my @headers = sort { $a <=> $b }
grep { !$seen{$_}++ }
map { keys %{ $hash{$_} } }
keys %hash;
# count how many rows each node has
my %number_of_rows;
foreach my $node ( keys %hash ) {
COUNT_ROWS: foreach my $header ( keys %{ $hash{$node} } ) {
$number_of_rows{$node} = scalar @{ $hash{$node}->{$header} };
last COUNT_ROWS;
}
}
my $workbook = Excel::Writer::XLSX->new('test.xlsx');
my $worksheet = $workbook->add_worksheet;
# write the headers and save the cols
my %col_headings;
$worksheet->write( 0, 0, 'Node' );
for ( my $i = 0; $i <= $#headers; $i++ ) {
$col_headings{ $headers[$i] } = $i + 1;
$worksheet->write( 0, $i + 1, $headers[$i] );
}
my $row = 1; # overall row in the Excel file
my $node_row = 0; # current row for the current node
NODE: foreach my $node ( sort keys %hash ) {
# write the node value (letter P, Q)
$worksheet->write( $row, 0, $node );
# iterate the columns ...
foreach my $header (@headers) {
# ... but only write one that has a value
$worksheet->write(
$row,
$col_headings{$header},
$hash{$node}->{$header}->[$node_row]
) if exists $hash{$node}->{$header};
}
$row++; # always go to a new row
if ( ++$node_row < $number_of_rows{$node} ) {
# but if we have not done all the rows for the current node,
# redo this node in a new row with the next node_row
redo NODE;
}
else {
# or reset the node_row
$node_row = 0;
}
}
使用严格;
使用“全部”警告;
使用Excel::Writer::XLSX;
我的%hash=(
‘P’=>{
'4' => [ '1/4/1 2', '1/4/1 3' ],
'2' => [ '1/2/1 1', '1/2/5 4' ]
},
‘Q’=>{
'4' => ['1/4/1 3'],
'3' => ['1/3/1 1'],
'5' => ['1/5/1 1']
},
);
我看到的百分比;
my@headers=sort{$a$b}
grep{!$seen{$}++}
映射{keys%{$hash{${}}
密钥%hash;
#计算每个节点有多少行
我的%u行数;
foreach my$节点(键%hash){
计数行:foreach my$头(键%{$hash{$node}}){
$number_of_rows{$node}=scalar@{$hash{$node}->{$header};
最后计数行数;
}
}
my$workbook=Excel::Writer::XLSX->new('test.XLSX');
我的$工作表=$工作簿->添加工作表;
#写标题并保存cols
我的%colu标题;
$worksheet->write(0,0,'节点');
对于(我的$i=0;$i写入(0,$i+1,$headers[$i]);
}
my$row=1;#Excel文件中的总行
my$node_row=0;#当前节点的当前行
节点:foreach my$节点(排序键%hash){
#写入节点值(字母P,Q)
$worksheet->write($row,0,$node);
#迭代列。。。
foreach my$header(@headers){
#…但只写一个有值的
$worksheet->write(
$row,
$col_headers{$header},
$hash{$node}->{$header}->[$node\u行]
)如果存在$hash{$node}->{$header};
}
$row++#始终转到新行
if(++$node_行<$number_行{$node}){
#但是如果我们没有完成当前节点的所有行,
#使用下一个节点\行在新行中重做此节点
重做节点;
}
否则{
#或者重置节点\行
$node_row=0;
}
}
这将使用您的代码查找所有标题。它指定哪个标题包含哪个列,并计算每个节点的行数。然后,它迭代节点,使用继续运行一个节点,直到该节点的所有行都已用尽。它通过保持当前节点行的递增计数器来完成此操作。同时,我们始终增加整个行计数器,使其在表中向下移动
这是它的样子
代码有点凌乱,但它完成了任务。看起来这是一个一次性运行的任务。输出用于屏幕,而不是CSV阅读器?@simbabque最后,我需要将其放入excel。示例输出完成了吗?是的,我相信是的。如果您有任何疑问,请告诉我?p下的所有数组是否总是有两个和两个Q下的所有数组都始终有一个元素?我不知道该如何使用。请提供一个完整的工作示例。您现在缺少一个右卷发,一旦添加它,它将以
Q数组(0x1cc0b20)\nARRAY(0x1cc09a0)