【问题标题】:How to get the max value from an array in Perl?如何从 Perl 中的数组中获取最大值?
【发布时间】:2016-05-20 16:07:03
【问题描述】:

我有一个输入源如下。我想要做的是将每条Layer 行上的数值捕获到一个数组中,然后打印出最大值。

输入

MACRO cell_1
 size 0.1 by 0.1 ; 

 pin a
 (....same topology as pin vcc)
 END a

 pin b
 (.....same topology as pin vcc)
 END b

 Pin vcc
  aaaa
  bbbb
  Port
   Layer m2 ;
  END
  CCC
  DDD
  Port 
   Layer m1 ;
  END
  EEE
  FFF
  Port
   Layer m0 ;
  END
 END vcc

 pin d
 (....same topology as pin vcc)
 END d
END cell_1

MACRO cell_2
(repeated)
END cell_2 

我的代码:

foreach my $file ( @files ) {   # @files = multiple path  of abc/def/fgh/cell_lef

    open( INFILE, "<$file" ) || die "Can not open stdcell_file\n";
    my @lines = <INFILE>;
    close INFILE;

    $init = 1;
    $delimiter =~ /^$/;      # between each MACRO. haven't utilize this yet

    foreach (@lines) {

        if ( $init ) {
            $path = 1;
            $init = 0;
            @num  = ();
        }

        if ( $path ) {

            if ( /MACRO\s+(\S+) /) {
                $cellname = $1; print "$cellname\n";
            }

            if ( /SIZE\s+(\S+)\s+(\S+)\s+(\S+)/ ) {
                $footprint_x = $1;
                $footprint_y = $3;
                print "$footprint_x $footprint_y\n";
            }

            if ( /PIN vcc/ .. /END vcc/ ) {

                #grab the highest value from layer (m*)
                #print "max layer = m*"
            }

            $init = 1;
        }
    }
}

预期输出

cell_1
0.1 0.1
m2

cell_2
0.2 0.2
m3

我尝试使用的代码:

if ( /PIN vcc/../END vcc/ ) {
    if ( /LAYER\s+m(\S+) / ) {
        push(@num, $1);
        print "@num";
    }                               
}    

到目前为止,我的代码的问题是,当我打印 @num 的值时,所有值都作为字符串 (210) 而不是单个元素连接在一起:2 1 0 — 所以我无法进行排序以获得最大值。

更新:我不确定如何将 while 集成到我的代码中,因为我使用 foreach 作为我的主循环

【问题讨论】:

  • 嵌套的 if 语句有点尴尬,但这应该可以。格式 - print join " ", @num; 可能会有所帮助 - 不应该影响排序(您没有显示)。
  • 在你的输出中,“0.2 0.2”这一行是从哪里来的?
  • @marty ,它不会反映在输入源中。它只是一个随机数来说明我的预期输出是什么样的
  • 您的print "@num" 是问题所在。这就是 Perl 打印数组的方式。进入调试模式并执行此操作以查看@num 数组:x @num。它会为每个数组项打印一行。

标签: perl


【解决方案1】:

您的代码可以捕获数字,只是您正在打印整个数组。当您打印数组时,Perl 的数组元素默认分隔符是 "",即什么都没有 - 所以,它看起来像一个字符串,但它是三个(或多个)元素彼此相邻打印,没有分隔符。

您可以使用while (&lt;&gt;) { 在 Unix 过滤器样式中逐行迭代输入。您可以在找到“PIN vcc”时打开“扫描模式”标志,并在找到“END vcc”时将其关闭。之后,使用正则表达式搜索图层行,但始终使用“扩展模式”/x,这样您就可以在正则表达式中使用空格。

由于用于切换模式和捕获层号的正则表达式是互斥的,您可以让其他检查在检查成功后进行 - 请注意,如果将来的更改导致重叠情况,您需要执行next当其中一个正则表达式成功时。

最后,List::Util 是一个核心模块,所以你不妨从中获取max function

use v5.12;
use warnings;
use List::Util qw( max );

my @num ;
my $scanning = 0;
while (<>) {
    $scanning = 1  if /PIN vcc/ ;
    $scanning = 0  if /END vcc/ ;
    next unless $scanning ;
    push @num, $1  if /Layer \s+ m (\d+) /x ;
}
say "Max layer number found: ", max(@num) ;

【讨论】:

  • if (/PIN vcc/../END vcc/) { 表示法会跳过包含 PIN vcc 的行之前的行(即使它们包含“层”行),也会跳过 END vcc 之后的行(即使它们包含“层”行)。可以有多个带有开始/结束标记的块;我相信他们最终都会受到同样的对待(也就是说,就好像他们都是一个大街区的一部分)。
  • 啊——现在我明白了。我已经相应地更新了我的答案。
  • 乔纳森·莱弗勒。你说的对 。我粘贴的输入源是文件中的重复单元。顺便说一下,我指的文件是 LEF 文件
  • 我正在尝试,但我不确定如何将所有建议集成到我的代码中:(。我确实尝试了@Сухой27 的建议,因为她的建议没有 while()。但输出是不是我想要的。让我更新更多代码/细节。再次希望您的帮助:(
  • 打印任何列表时的默认分隔值(存储在$,) - 无论它是否包含在数组中 - 确实是空字符串。但是,这不是 OP 所做的。他的代码显示print "@num";,而不是print @num;。插入数组时,默认分隔值(存储在$" 中)是包含单个空格字符的字符串。除非 OP 在他的代码中的其他地方使用 $",否则 print "@num"; 应该打印数组的所有元素,用空格分隔。
【解决方案2】:

或者干脆使用sort函数来做。

my @values ;
while (<DATA>) 
{    
       push (@values , $1) if (/Layer\s+m(\d+)\s;/);
}
my ($max) = sort{$b <=> $a} @values ;
print "$max\n";

__DATA__
Pin vcc
aaaa
bbbb
Port
  Layer m3 ;
END
CCC
DDD
Port 
  Layer m1 ;
END
EEE
FFF
Port
  Layer m0 ;
END

使用sort函数并将第一个结果存储到包含变量$max的列表中。

【讨论】:

    【解决方案3】:
    my @data = <DATA> ;
    my @num ;
    
    foreach (@data) {
     push @num, $1 if /Layer\s+m(\S+)/ ;
    } 
    # home made max() - sorts an anonymous array and prints the last element
    print [ sort { $a <=> $b } @num ]->[-1] , "\n" ;
    
    __DATA__
    Pin vcc
    aaaa
    bbbb
    Port
      Layer m2 ;
    END
    CCC
    DDD
    Port 
      Layer m1 ;
    END
    EEE
    FFF
    Port
      Layer m0 ;
    END
    END vcc
    

    【讨论】:

      【解决方案4】:

      使用map 从文件中获取数字。 sort数量并获取最大数量。

      #!/usr/bin/perl
      use strict;
      use warnings;
      
      my $max = (sort{$b <=> $a }map{/Layer\s+m(\d+)/} <DATA>)[0];
      print $max,"\n";
      
      __DATA__
      Pin vcc
      aaaa
      bbbb
      Port
        Layer m3 ;
      END
      CCC
      DDD
      Port 
        Layer m1 ;
      END
      EEE
      FFF
      Port
        Layer m0 ;
      END
      

      【讨论】:

        【解决方案5】:

        首先,如果您只寻找最大值,则不需要存储所有值;其次,在循环结束后打印最大值,

        my $max = "-inf";
        if (/PIN vcc/ .. /END vcc/) {
            $max = $1 if /LAYER\s+m(\S+)/ and $max < $1;
        }
        
        # ..
        print $max, "\n";
        

        【讨论】:

        • 嗨 Сухой27,你能解释一下这是什么意思吗?和 $max
        • @TerryChengFeiYang $max以无限负值开头,然后检查$1(正在捕获(\S+)的组)是否大于$max
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-18
        • 2011-10-04
        • 1970-01-01
        • 1970-01-01
        • 2020-10-29
        • 2010-09-08
        相关资源
        最近更新 更多