【问题标题】:How to print the array of arrays in perl - reference variable如何在 perl 中打印数组数组 - 引用变量
【发布时间】:2013-08-18 21:36:36
【问题描述】:
#! /usr/bin/perl 
use strict;
use warnings;
use File::stat;

my $file_name = 0;
my $info = 0;
my $ret_mode = 0;
my $size;
my $last_mod;
my @array_file;
my $index = 0;
my @array_mode;
my @array_size;
my @array_last_mod;
foreach(@ARGV){
  $file_name = $_;
  $info = stat($file_name);
  $size = $info->size;
  $last_mod = scalar(localtime($info->mtime));
  $ret_mode  = $info->mode;
  $ret_mode = $ret_mode & 0777;
  $array_file[$index] = ($file_name);
  $array_mode[$index] = ($ret_mode);
  $array_size[$index] = ($size);
  $array_last_mod[$index] = ($last_mod);
  $ret_mode = 0;
  $index++;
 }
 my @array_arrays = (@array_file, @array_mode, @array_size, @array_last_mod);
 my $array_ref = \@array_arrays;
 my $i = 0;
 for(@$array_ref){
  print "@$array_ref[$i]\n";
  $i++;
 }

我创建了一个数组数组,我想从创建的数组数组中打印文件名、mmode、大小和上次访问时间。它不打印任何值,

 for(@$array_ref){
  print "@$array_ref[$i]\n";
  $i++;
 }

【问题讨论】:

标签: perl


【解决方案1】:
my @array_arrays = (@array_file, @array_mode, @array_size, @array_last_mod);

此语句不会创建数组数组。相反,它将各种数组扁平化为一个大的扁平列表,然后将其分配给@array_arrays。您要分配数组引用。用引用运算符\获取:

my @array_arrays = (\@array_file, \@array_mode, \@array_size, \@array_last_mod);

或使用快捷方式

my @array_arrays = \(@array_file, @array_mode, @array_size, @array_last_mod);

即便如此,您最后的foreach-loop 还是错误的。你可能是说

for my $i (0 .. $#{ $array_arrays[0] }) {
  for my $aref (@array_arrays) {
    print $aref->[$i], "\n";
  }
}

或类似的东西。


您的代码风格可以改进。

  • 请不要在顶部声明所有变量。在尽可能严格的范围内声明它们。尝试在初始化时声明它们,例如

    for my $file_name (@ARGV) {
      my $info = stat($file_name);
      my size = $info->size;
      ...
    }
    
  • 不要在数组名称前加上 array_@ sigil 和/或带有 [...] 运算符的下标清楚地表明这些是数组。

  • $ret_mode & 0777 – 结果应该是 $ret_mode 本身:07770b111111111。 IE。这将删除除最后 9 位之外的所有位 - 您不会关心左侧是否还有更多。

  • $last_mod = scalar(localtime($info->mtime)); – 由于标量分配,localtime 已在标量上下文中执行。无需明确说明。

  • my $index = 0; ... for (...) { $array[$index] = ...; $index++ }。请不要。只需使用pushfor (...) { push @array, ... }。除非必须,否则不要自己维护索引。

  • $ret_mode = 0; 为什么?无论如何,您在下一次迭代期间分配一个新值。请注意,您应该在循环内声明此变量(请参阅我关于紧密范围的观点),这将在每次迭代中创建一个新变量,从而使这更加无用。

  • my $array_ref = \@array_arrays; .. @$array_ref[$i]。这不是有点倒退吗? $array_arrays[$i] 也可以。请注意,在您的辩护中,@ 可能是错误的标志。你的意思是$$array_ref[$i]

【讨论】:

    【解决方案2】:

    让我们尝试一些不同的东西。

    首先,有一个很好的语法使用-> 来引用数组和散列。在这里,我将制作一组人。我将创建一个包含该人所有信息的 %person 哈希:

    my %person;
    my $person{NAME} = "Bob";
    my $person{JOB}  = "Programmer";
    my $person{PHONE} = "555-1234";
    

    现在,我将它放入一个数组中:

    my @array
    my $array[0] = \%person;
    

    我可以这样引用数组中的人:

    print ${$array[0]}{NAME} . "\n";   #Prints Bob
    print ${$array[0]}{JOB} . "\n";    #Prints Porgrammer
    

    但是,Perl 给了我一个很好的干净的方法来做到这一点:

    print $array[0]->{NAME} . "\n";    #Prints Bob
    print $array[0]->{JOB}  . "\n";    #Prints Progammer
    

    事实上,我可以一起跳过散列。在这里,我将 Jill 添加到我的数组中:

    $array[1]->{NAME} = "Jill";
    $array[1]->{JOB}  = "DBA";
    $array[1]->{PHONE} = "555-5555";
    

    您可以看到这是使用引用的一种更简单的方法。更容易看到正在发生的事情并且需要更少的代码行。

    你可以像这样引用数组的数组:

    $myarray[1]->[3] = 42;
    

    或者有一个存储数组的散列。在这个时代,谁只有一个电话号码?:

    $person[1]->{PHONE}->[0] = "555-4567";
    $person[1]->{PHONE}->[1] = "555-4444";
    

    或者,为了让它更复杂,我们可以有一个数组散列的散列:

    $person[1]->{PHONE}->{CELL}->[0] = "555-1111";
    $person[1]->{PHONE}->{CELL}->[1] = "555-2222";
    $person[1]->{PHONE}->{HOME}->[0] = "555-3333";
    $person[1]->{PHONE}->{JOB}->[0] = "555-4444";
    $person[1]->{PHONE}->{JOB}->[1] = "555-5555";
    

    使用这种语法确实有助于清理大量代码。您不必将信息存储到单独的结构中,然后仅用于参考。相反,您可以按照您想要的方式简单地设置您的结构,而无需中间步骤。

    现在解决您的问题:您正试图将有关文件的一堆信息存储到一系列数组中。您希望$array_mode[1]$array_file[1] 一起使用,并且您必须使所有这些数组保持同步。这是一种痛苦,而且很复杂。

    使用引用的全部目的是消除对多个变量的需求。如果您要使用引用,为什么不简单地将整个文件结构存储到一个数组中。

    你真正想要的是一个哈希引用数组。并且,该哈希引用将根据您的文件 属性 进行键入。这是您的代码重组为使用哈希引用数组。我什至没有费心去检查它的其余部分。例如,我不确定您的 localtime 将如何工作:

    use strict;
    use warnings;
    use feature qw(say);
    use File::stat;
    
    my @files;
    for my $file ( @ARGV ) {
        my $info = stat( $file );
        my $file = {};       #This will be a reference to a hash
        $file->{NAME} = $file;
        $file->{SIZE} = $info->size;
        $file->{RET_MODE} = $info->mode & 0777;
        $file->{LAST_MOD} = localtime $info->mtime;  #Does this work?    
        push @files, $file    #Pushes the hash reference onto the array
    }
    

    这样更短更干净。另外,您知道$files[0]->{NAME}$files[1]->{SIZE} 一起使用,如果您从数组中删除$files[0],或将其转移到另一个变量,该文件的所有属性都会一起出现。

    打印出来的方法如下:

    for my $file ( @files ) {
        say "File Name: " . $file->{NAME};
        say "File Size: " . $file->{SIZE};
        say "Last Modified: " . $file->{LAST_MOD};
        say "File Mode: " . $file->{RET_MODE};
    }
    

    简单易做。


    但是,我认为你真正想要的是 hashhash。让你的文件名成为你主哈希的键,让{SIZE}{LAST_MOD}{RET_MODE}成为你的子哈希的键:

    my %files = {};   #This is a hash of hashes
    for my $file_name ( @ARGV ) {
        my $info = stat( $file );
        $files{$file_name}->{SIZE} = $info->size;
        $files{$file_name}->{RET_MODE} = $info->mode & 0777;
        $files{$file_name}->{LAST_MOD} = localtime $info->mtime;  #Does this work?    
    }
    

    现在如果有人问,foo.txt 最后一次修改是什么时候?”,你可以说:

    say "File 'foo.txt' was last modified on " . $file{foo.txt}->{LAST_MOD};
    

    并打印出你的整个结构:

    for my $file_name ( sort keys %files ) {
        say "File: $file_name";
        for my attribute ( sort keys %{ $file_name } ) {
            say "    $attribute: " . $files{$file_name}->{$attribute};
        }
    }
    

    下一步是了解Object Oriented Perl!面向对象的 Perl 使用这些类型的引用,但会大大简化对这些引用的处理,从而减少编程错误。

    【讨论】:

      猜你喜欢
      • 2023-04-05
      • 2012-06-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-02-25
      • 2011-03-02
      • 1970-01-01
      相关资源
      最近更新 更多