-1

这将比解释更容易在代码中显示。我刚刚得到一个哈希映射来快速填充哈希以对脚本读取的数据运行替换。例如,如果 5 输出 6,如果 3 输出 2,如果 23 输出 6,等等。除了不映射之外,这工作得很好钥匙之一。

(顺便说一句,如果有人能想到一种更优雅的方式将哈希中的多个键映射到单个值,请告诉我:))

无论如何到代码...

$COLUMN = 6;

%PERIOD_1 = (map {(  1, 10, 14, 20, 22, 29, 35, 39 )[$_] => 1 } 0..100); #1st period
%PERIOD_2 = (map {(  3, 8, 11, 18, 24, 26, 32, 37  )[$_] => 2 } 0..100); #2nd period
%PERIOD_3 = (map {(  7, 13, 16, 21, 28, 34, 36     )[$_] => 3 } 0..100); #3rd period
%PERIOD_4 = (map {(  5, 2, 6, 15, 17, 23, 27, 31,38)[$_] => 4 } 0..100); #4th period
%PERIOD_5 = (map {(  4, 9, 12, 19, 25, 30, 33, 40  )[$_] => 5 } 0..100); #5th period

%PERIODS = (%PERIOD_1,%PERIOD_2,%PERIOD_3,%PERIOD_4,%PERIOD_5);

open (FILE,"<",$ARGV[0]);

while(<FILE>) {
   my @columns = split(/\t/);
   print $columns[$COLUMN] . "-" . $PERIODS{$columns[$COLUMN]};
} 

close(FILE);

所以这很好用。您会得到如下输出:

37-2
29-1
15-4
6-4
34-3
24-2
5-

它匹配/替换除了 5之外的每个值。我不明白 - 映射中的所有其他键都在哈希中,但出于某种原因,5(并且只有 5)不是。有人可以解释问题是什么吗?编辑:固定格式

编辑:是的,我在代码中使用了警告。不过,我真的不在乎警告(即使它与我的问题有关)-我只想解决问题。如果我愿意理解这个警告,我会问的。

4

2 回答 2

3

这是一些相当不寻常的代码,它可能没有按照你的想法做。例如:

%PERIOD_2 = (map {(  3, 8, 11, 18, 24, 26, 32, 37  )[$_] => 2 } 0..100);

这将遍历从 0 到 100 的数字,但您只对 0 到 7 感兴趣,因为列表包含 8 个数字。例如,8 的下标将为空,映射迭代将返回() => 2,或仅返回一个 2。这意味着您将得到一个长字符串2,2,2,2,2,2,2,这将导致密钥2始终存在于该哈希中,不不管它是否在列表中。

这是将列表转换为哈希的一种过于复杂的方法。你通常会这样做:

my %hash = map { $_ => 2 } (  3, 8, 11, 18, 24, 26, 32, 37 );

如果你有几个列表要合并到一个哈希中,你会这样做

my %hash;
for my $num (1, 10, 14, 20, 22, 29, 35, 39) {
    $hash{$num} = 1;
}
for my $num (3, 8, 11, 18, 24, 26, 32, 37) {
    $hash{$num} = 2;
}
....

如果你用过

use strict;
use warnings;

您很可能不会遇到此问题,因为您会收到Odd number of elements in hash assignmenttoolic指出的警告。

另外,在这种情况下,使用Data::Dumper模块进行调试非常方便:

use Data::Dumper;
print Dumper \%hash;   # send ref to hashes and arrays

对于您上面的代码,使用这些调试工具,您将获得以下输出:

Odd number of elements in hash assignment at foo.pl line 9.
$VAR1 = {
          '32' => 2,
          '11' => 2,
          '3' => 2,
          '26' => 2,
          '2' => undef,
          '8' => 2,
          '18' => 2,
          '24' => 2,
          '37' => 2
        };

正如你所看到的,问题是立即可以识别的:密钥2没有价值。

当您将哈希值相加时,您还会覆盖以前的有效值,例如 for 的值5。例如:

%hash1 = (5 => 2);
%hash2 = (5 => undef);
%hash  = (%hash1, %hash2);

由于哈希键是唯一的,5 => undef因此将覆盖5 => 2.

警告指的"Odd number of elements"是分配给散列的列表,而不是键的数量。例如:

my %foo = (1, 2, 3);  # odd number of elements

这个散列现在有键13,但键3没有值,所以它是undef。通常在散列分配中,您需要偶数个元素,以便每个键都有一个值。

于 2013-09-26T16:07:47.590 回答
2

你应该永远

use strict;
use warnings;

在你的程序的顶部,并声明每个变量my尽可能接近它的第一个使用点。

您还应该最好只使用小写和下划线作为变量名。大写是为包名等全局标识符保留的。

最好使用词法文件句柄而不是全局句柄,并且您应该始终检查调用是否成功,并随着字符串中open的值而死亡。像这样$!die

open my $file, '<', $ARGV[0] or die "Unable to open input file: $!";

这会做什么

my %period = (map {(  1, 10, 14, 20, 22, 29, 35, 39 )[$_] => 1 } 0..100);

为列表中的这些元素正确生成键/值对,但是当您达到 8(列表的大小)时,它只会生成值1,因为列表中没有相应的元素。所以你得到

 1 => 1,
10 => 1,
14 => 1,
20 => 1,
22 => 1,
29 => 1,
35 => 1,
39 => 1,
1,
1,
1,
1,
1,

对于列表中有偶数个元素的散列,您最终会得到一个不成对的尾随值。

我建议您将信息放入数据文件中,或者至少放入__DATA__程序的部分中,然后像这样将其读入哈希中

use strict;
use warnings;

my $column = 6;

my %periods;
while (<DATA>) {
  my ($val, @keys) = /\d+/g;
  next unless $val;
  $periods{$_} = $val for @keys;
}

open my $fh, "<", $ARGV[0];

while(<$fh>) {
  my @columns = split /\t/;
  my $key = $columns[$column];
  printf "%s - %s\n", $key, $periods{$key};
} 

__DATA__
1:  1, 10, 14, 20, 22, 29, 35, 39;
2:  3,  8, 11, 18, 24, 26, 32, 37;
3:  7, 13, 16, 21, 28, 34, 36;
4:  5,  2,  6, 15, 17, 23, 27, 31, 38;
5:  4,  9, 12, 19, 25, 30, 33, 40;

(不要担心后面的行的格式__DATA__。它只注意行中的十进制数字。其他一切都只是布局,被忽略。)

于 2013-09-26T16:29:56.533 回答