文件处理 perl - split 产生非常小的数组

File processing perl - split produces very small arrays

美好的一天。我有一个大文本文件要处理,组织方式如下:

A
B 87368911
C 165368993    165369000       165369007       165369014       165369021       165369028
D 3299941
E 3221521
F 5909327
G 14740025      14740019        14740031        14740037
H 4446477      4640745

我想把它拆分成数组的散列,以第一列为键,如果有可迭代数组中的值(对于 A,有 none ,如您所见)。为此,我制作了如下代码(略有截肢,我明明打开文件有周边代码):

my %resolvedreads;

while (my $line = <IN>) {
    my @thisline = $line =~ m/(\S+)/g;
    $resolvedreads{$thisline[0]} = @thisline[1 .. $#thisline];
    print join "\t", @{$resolvedreads{$thisline[0]}}, "\n";
}

我什至没有真正测试过这个,因为它看起来太微不足道了。显然我应该有,因为它给了我这个:

Use of uninitialized value $thisline[0] in hash element at resolved_reads_purifier.pl line X-1, <IN> line 1.
Use of uninitialized value $thisline[0] in hash element at resolved_reads_purifier.pl line X, <IN> line 1.
Can't use an undefined value as an ARRAY reference at resolved_reads_purifier.pl line X, <IN> line 1.

我发现自己对此有些困惑。进一步调查发现,该行确实被拆分了,但是每个数组的长度都是1或2。

那么是什么原因呢?我觉得我在这里错过了一些基本的东西,而且我已经无能为力了。尽管在我看来几乎完全相同,但我之前的代码实际上已编译。

$resolvedreads{$thisline[0]} = @thisline[1 .. $#thisline];

将一个数组赋值给一个标量上下文中的哈希值,其实和

是一样的
$resolvedreads{$thisline[0]} = scalar @thisline[1 .. $#thisline];

$resolvedreads{$thisline[0]} = $#thisline;

$resolvedreads{$thisline[0]} = $thisline[$#thisline];

从你的其余部分 post 看来你想为散列值分配一个数组引用

$resolvedreads{$thisline[0]} = [ @thisline[1 .. $#thisline] ];

同样,您可以将列表分配给列表上下文中的列表

@{$resolvedreads{$thisline[0]}} = @thisline[1 .. $#thisline];

所以我看到了几件事。上面提到的分配数组时的标量与列表上下文。另一件事是您的切片 [1...#@array] 以“1”开头,但 A 行不存在索引 1,因此您的错误消息。这是工作代码:

use Modern::Perl '2013';
use Data::Dumper;

my $text = 'A
B 87368911
C 165368993    165369000       165369007       165369014       165369021       165369028
D 3299941
E 3221521
F 5909327
G 14740025      14740019        14740031        14740037
H 4446477      4640745';

my $fh;
open($fh, '<', $text);

my %resolvedreads;

while (my $line = <$fh>) {
  chomp $line;
  my @thisline = $line =~ m/(\S+)/g;
  my $index    = shift @thisline;
  $resolvedreads{$index} = \@thisline;

}

say Dumper(\%resolvedreads);

问题是,当一个文件记录只有一个字段时,$#thisline 为零,所以 @thisline[1 .. $#thisline]@thisline[1 .. 0],这是一个空列表。将其分配给给定的标量 undef

除此之外还有一个问题

$resolvedreads{$thisline[0]} = @thisline[1 .. $#thisline]

因为您将一个列表分配给一个标量,您通常只会得到列表的最后一个元素,即 $thisline[-1]。此时你真的应该分配一个数组引用

这就是我对您的问题进行编码的方式

use strict;
use warnings;

my %resolvedreads;

while ( <DATA>) {
    my ($key, @values) = split;
    next unless defined $key;        # Skip blank records
    $resolvedreads{$key} = \@values;
}

use Data::Dump;
dd %resolvedreads;

__DATA__
A
B 87368911
C 165368993    165369000       165369007       165369014       165369021       165369028
D 3299941
E 3221521
F 5909327
G 14740025      14740019        14740031        14740037
H 4446477      4640745

输出

{
  A => [],
  B => [87368911],
  C => [165368993, 165369000, 165369007, 165369014, 165369021, 165369028],
  D => [3299941],
  E => [3221521],
  F => [5909327],
  G => [14740025, 14740019, 14740031, 14740037],
  H => [4446477, 4640745],
}