Perl 从数组散列中读取列
我是perl新手,有一个关于使用数组哈希来检索特定列的问题。我的代码如下:Perl 从数组散列中读取列,perl,hash,perl-data-structures,Perl,Hash,Perl Data Structures,我是perl新手,有一个关于使用数组哈希来检索特定列的问题。我的代码如下: my %hash = ( name1 => ['A', 'A', 'B', 'A', 'A', 'B'], name2 => ['A', 'A', 'D', 'A', 'A', 'B'], name3 => ['A', 'A', 'B', 'A', 'A', 'C'], ); #the values of %hash are
my %hash = ( name1 => ['A', 'A', 'B', 'A', 'A', 'B'],
name2 => ['A', 'A', 'D', 'A', 'A', 'B'],
name3 => ['A', 'A', 'B', 'A', 'A', 'C'],
);
#the values of %hash are returned as arrays not as string (as I want)
foreach my $name (sort keys %hash ) {
print "$name: ";
print "$hash{$name}[2]\n";
}
for (my $i=0; $i<$length; $i++) {
my $diff = "no";
my $letter = '';
foreach $name (sort keys %hash) {
if (defined $hash{$name}[$i]) {
if ($hash{$name}[$i] =~ /[ABCD]/) {
$letter = $hash{$name}[$i];
}
elsif ($hash{$name}[$i] ne $letter) {
$diff = "yes";
}
}
if ( $diff eq "yes" ) {
foreach $name (sort keys %hash) {
if (defined $hash{$name}[$i]) { $newhash{$name} .= $hash{$name}[$i]; }
}
}
}
}
foreach $name (sort keys %newhash ) {
print "$name: $newhash{$name} \n";
}
但只有这样一个信息:
在test_hash.pl第31行的字符串ne中使用未初始化值$letter
有人对此有想法吗?
干杯
编辑:
非常感谢你在这个问题上的帮助
我编辑了我的帖子,以确认frezik,Dan1111,Jean的建议。你是对的,现在没有警告,但我也无法从print语句中获得任何输出,对此我没有任何线索
@TLP:好的,我只是生成一组随机的列,没有任何排序目的。我真正想要的是字母如何变化,这意味着如果对于相同的数组索引(存储在散列中),字母是相同的,则丢弃这些字母,但是如果键之间的字母不同,我希望将该索引列存储在新的散列中
干杯。您的标量
$letter
未定义。添加此项以消除警告
my $letter='';
上面的正则表达式将匹配一个字符串,如\uuuu ABCD\uuuu
或ABCD1234
,但决不会单独匹配a
或B
。您可能想要匹配这些字母中的任何一个,并且锚定正则表达式也是一个好主意:
if ($hash{$name}[$i] =~ /\A [ABCD] \z/x) {
(x选项意味着忽略空白,这有助于使正则表达式更易于阅读。)
在上面的示例中,当
$i==2
且内部循环碰巧先按了name1
或name3
键时,仍然会得到警告。由于正则表达式与t
不匹配,$letter
将保持未初始化状态。我假设通过此操作,您希望匹配字母A、B、C或D中的任意一个:
if ($hash{$name}[$i] =~ /ABCD/)
但是,如前所述,它与字符串“ABCD”完全匹配。您需要一个角色类来满足您的需要:
if ($hash{$name}[$i] =~ /[ABCD]/)
但是,您还存在其他逻辑问题,这可能导致您在设置之前与$letter
进行比较。将其设置为空(正如Jean所建议的)是一个简单的选项,可能会有所帮助
另一个问题是:
print "$name: @{ $newhash{$name} }\n";
%newhash
不是数组哈希,因此需要删除数组取消引用:
print "$name: $newhash{$name} \n";
我认为逐字核对是错误的。收集所有信件并立即检查似乎更容易。然后,模块的uniq函数可以快速确定字母是否变化,并且可以轻松地将它们转换为结果哈希
use strict;
use warnings;
use Data::Dumper;
use List::MoreUtils qw(uniq);
my %hash = ( name1 => ['A', 'A', 'B', 'A', 'A', 'B'],
name2 => ['A', 'A', 'D', 'A', 'A', 'B'],
name3 => ['A', 'A', 'B', 'A', 'A', 'C'],
);
my @keys = keys %hash;
my $len = $#{ $hash{$keys[0]} }; # max index
my %new;
for my $i (0 .. $len) {
my @col;
for my $key (@keys) {
push @col, $hash{$key}[$i];
}
if (uniq(@col) != 1) { # check for variation
for (0 .. $#col) {
$new{$keys[$_]} .= $col[$_];
}
}
}
print Dumper \%new;
输出:
$VAR1 = {
'name2' => 'DB',
'name1' => 'BB',
'name3' => 'BC'
};
您可能对这个替代解决方案感兴趣
use strict;
use warnings;
my %hash = (
name1 => ['A', 'A', 'B', 'A', 'A', 'B'],
name2 => ['A', 'A', 'D', 'A', 'A', 'B'],
name3 => ['A', 'A', 'B', 'A', 'A', 'C'],
);
my @columns;
for my $list (values %hash) {
$columns[$_]{$list->[$_]}++ for 0 .. $#$list;
}
my %newhash = %hash;
for my $list (values %newhash) {
$list = join '', map $list->[$_], grep keys %{$columns[$_]} > 1, 0 .. $#$list;
}
use Data::Dump;
dd \%newhash;
输出
{ name1 => "BB", name2 => "DB", name3 => "BC" }
太好了。非常感谢你在这个问题上的帮助 我尝试了一个基于TLP建议的代码,效果很好。因为我对perl比较陌生,所以我认为这段代码比Borodin的代码更容易理解。我所做的是:
#!/usr/bin/perl
use strict;
use warnings;
use List::MoreUtils qw(uniq);
my %hash = ( name1 => ['A', 'A', 'T', 'A', 'A', 'T', 'N', 'd', 'd', 'D', 'C', 'T', 'T', 'T'],
name2 => ['A', 'A', 'D', 'A', 'A', 'T', 'A', 'd', 'a', 'd', 'd', 'T', 'T', 'C'],
name3 => ['A', 'A', 'T', 'A', 'A', 'C', 'A', 'd', 'd', 'D', 'C', 'T', 'C', 'T'],
);
my @keys = keys %hash;
my $len = $#{ $hash{$keys[0]} }; # max index
my %new;
for (my $i=0; $i<$length; $i++) {
my @col;
for my $key (@keys) {
if ($hash{$key}[$i] =~ /[ABCDT]/) { #added a pattern match
push @col, $hash{$key}[$i];
}
}
if (uniq(@col) != 1) { # check for variation
for (0 .. $#col) {
$new{$keys[$_]} .= $col[$_];
}
}
}
foreach my $key (sort keys %new ) {
print "$key: $new{$key}\n";
}
似乎没有保留键=>值的初始顺序。有人对此有任何暗示吗
干杯。您对“变量列”的定义是什么。看起来您需要除A之外的所有字母,或者可能需要第3列和第6列中的字母。或者每三个字母。但是从你的代码中,我不知怎么地得到了这样的印象,那就是字母的变化。那么是哪一个呢?好的,那么你想比较不同的数组,如果一列变成“AAA”或“BBB”,跳过它。但是,您必须先保存字母,然后进行检查。准确地说,但我认为我是在变量$letter中保存字母。然而,似乎没有将这些添加到新的哈希中。。。
{ name1 => "BB", name2 => "DB", name3 => "BC" }
#!/usr/bin/perl
use strict;
use warnings;
use List::MoreUtils qw(uniq);
my %hash = ( name1 => ['A', 'A', 'T', 'A', 'A', 'T', 'N', 'd', 'd', 'D', 'C', 'T', 'T', 'T'],
name2 => ['A', 'A', 'D', 'A', 'A', 'T', 'A', 'd', 'a', 'd', 'd', 'T', 'T', 'C'],
name3 => ['A', 'A', 'T', 'A', 'A', 'C', 'A', 'd', 'd', 'D', 'C', 'T', 'C', 'T'],
);
my @keys = keys %hash;
my $len = $#{ $hash{$keys[0]} }; # max index
my %new;
for (my $i=0; $i<$length; $i++) {
my @col;
for my $key (@keys) {
if ($hash{$key}[$i] =~ /[ABCDT]/) { #added a pattern match
push @col, $hash{$key}[$i];
}
}
if (uniq(@col) != 1) { # check for variation
for (0 .. $#col) {
$new{$keys[$_]} .= $col[$_];
}
}
}
foreach my $key (sort keys %new ) {
print "$key: $new{$key}\n";
}
name1: AAAAADCT
name2: AAAAADCT
name3: AAAAT