【问题标题】:Need help understanding this row-by-row file processor需要帮助了解此逐行文件处理器
【发布时间】:2011-12-19 02:11:46
【问题描述】:

我正在尝试使用下载的 Perl 代码,其中包括用于逐行读取输入文件的以下部分。

但是,我不太明白它是如何工作的

  1. $row[-1] 代表什么?可以从-1 索引行吗?

  2. $result{$id}{$group[0]}=$group[1]; 是如何工作的?是为结果构建二维数组吗?

  3. $df{$group[0]}++; 有什么作用?和 C++ 中的++ 一样吗?

my $result =();
my $df = ();

while (<FILE>)
{    
   my @row = split;
   my $id = $row[-1];
   for my $i(0 .. $#row - 2)
   {
      my @group = split(/\:/, $row[$i]);
      $result{$id}{$group[0]}=$group[1];
      $df{$group[0]}++;
   }
 }

【问题讨论】:

  • 您下载的代码是由不太了解 Perl 的人编写的。试图将一个空列表分配给一个标量是很愚蠢的。冒号不是正则表达式中的元数据,也不需要转义。
  • @tadmc : 至少他们已经对变量进行了词法作用域:)

标签: perl


【解决方案1】:

以下是该代码工作原理的简要说明。

  • 定义$result$df。并且出于某种奇怪的原因,尝试为它们分配一个空列表,即使它什么也没做。

    my $result =();
    my $df = ();
    
  • FILE 文件句柄中读取一行,并将其放入$_,对于每一行。

    while (<FILE>)
    {
    
  • 在空白处拆分$_,如果第一个元素为空白,则删除它。

      my @row = split;
    
  • $id 设置为@row 的最后一个元素。

      my $id = $row[-1];
    
  • 循环@row 的所有索引,除了最后两个,并将$i 设置为索引。如果前面的操作是pop 结尾的最后一个元素,这将更容易编写。我认为应该是$#row-1

      for my $i(0 .. $#row - 2)
      {
    
  • @row 在位置$i 处拆分元素,由: 进行。

        my @group = split(/\:/, $row[$i]);
    
  • 索引到%result(不是$result)。

    首先是$id,然后是@group 的第一个元素。将其设置为@group 的第二个值。

        $result{$id}{$group[0]}=$group[1];
    
  • %df(不是$df)的元素增加@group 的第一个值。如果之前不存在,它最终会将其设置为 1

        $df{$group[0]}++;
    
  • for 结束,然后 while 循环。

      }
    }
    

这就是我的写法。

use strict;
use warnings;
use autodie;

my $filename = 'filename';
open my $fh, '<', $filename;

my %result;
my %df;

while (<$fh>){
  my @row = split;
  my $id = pop @row;
  pop @row; # I assume this should be removed.
  for my $pair (@row){
    my($key,$value) = split(':', $pair);
    $result{$id}{$key} = $value;
    $df{$key}++;
  }
}

【讨论】:

  • 另外值得注意的是/\:/中的\ 是多余的
  • @Zaid 如果我再次编辑这篇文章,我会添加一个注释。但这并不是真正的问题,因为它们都可以工作。
  • 你有我的 +1。很棒的演练。
【解决方案2】:

有时最好通过示例来解释代码。

给定一个包含以下行的文件:

AA:BB CC:DD     CC:DD UNIMPORTANT_COL ID

%result 哈希看起来像:

(
    ID => {
            AA => 'BB',
            CC => 'DD',
          },
)

%df 哈希正在计算唯一实例的数量:

(
    AA => 1,
    CC => 2,
)

旁注

  • $#row@row 的最后一个索引,在上例中为 4。这意味着可以使用$row[$#row] 而不是$row[-1]
  • my ( $key, $value ) = split /:/, $group; 并使用它们代替$group[0]$group[1] 会更清楚
  • $i 变量在这里不是很有用。考虑改用foreach my $group ( @group[0..$#group-2]) {

【讨论】:

  • 如果my $id = $row[-1]; 被替换为my $id = pop @row;pop @row; 那么它可能是for my $group (@group){ ... }
【解决方案3】:
  1. $row[-1] 表示@row 数组的最后一个元素($row[-2] 将表示之前的元素,依此类推)

  2. $result{$id}{$group[0]}=$group[1] 使用一堆 perl 快捷方式,实际上它与$result-&gt;{$id}-&gt;{$group[0]} = $group[1] 相同。

    意思如下:

    • $result视为对HASH的引用,在该HASH中找到与键$id关联的元素,如果没有这样的元素,则新建一个
    • 将该元素视为对 HASH 的引用,在该 HASH 中找到与键 $group[0] 关联的元素,如果没有此类元素,则创建新元素
    • $group[1] 的值分配给该元素

    所以$result 是对 HASH 的 HASH 的引用。 (在Perl Data Structures Cookbook 中查看更多信息)

  3. $df{$group[0]}++; 增加 $df 引用的 HASH 中键 $group[0] 的值。与C++不同的是,当key没有关联值时,该值被视为0

【讨论】:

    【解决方案4】:
    1. 显然id是行的最后一列,$row[-1]返回@row数组的最后一个元素。

    2. $result{$id}{$group[0]}=$group[1] 通过将值 $group[1] 分配给键 $id$group[0] 的组合来构建二维 HASH

    3. 自增运算符 (++) 的工作方式与 C++ 中的相同

    【讨论】:

    • Perl 的后增量 (++) 并不总是与 C++ 一样工作。例如,此命令perl -e'$a=q[a];print$a++ for 1..3' 打印abc
    • 同样使用1.而不是1)在Markdown中创建一个列表。拥有超过 16k 的代表,您现在应该知道这一点。
    猜你喜欢
    • 2013-10-09
    • 1970-01-01
    • 2010-11-04
    • 2023-03-09
    • 2013-03-17
    • 1970-01-01
    • 1970-01-01
    • 2013-09-07
    • 1970-01-01
    相关资源
    最近更新 更多