英文:
Extend Array in Hashes of Arrays
问题
以下是您要翻译的代码部分:
我将字符串解析为HTML并从中提取表格。
表格有两列:第1列单一(键),第2列多值(值)
我想将这些值存储到散列中的数组中。
use strict;
use warnings;
use Data::Dumper qw(Dumper);
my $html='
<p class="auto-cursor-target"><br /></p>
<table class="wrapped">
<colgroup><col style="width: 50.0px;" /><col style="width: 29.0px;" />
</colgroup>
<tbody>
<tr><th><p>Wikispace</p></th><th><p>right</p></th></tr>
<tr><td>mimi</td><td>right1</td></tr>
<tr><td colspan="1">mama</td><td colspan="1">right3,right2</td></tr>
</tbody>
</table>
<p class="auto-cursor-target"><br /></p>
'';
use HTML::TableExtract;
my $te = HTML::TableExtract->new( headers => [qw(Wikispace right)] );
$te->parse($html);
my %known;
foreach my $ts ($te->tables) {
   foreach my $row ($ts->rows) {
     print @$row[0], ":::", @$row[1], ":  ";
     foreach my $val (split(/,/,@$row[1])) {
             print $val, ";";
             if (! $known{@$row[0]}) {
               my @arr = ($val);
               @known{@$row[0]}=\@arr;
             } else {
                     # my @arr = \@known{@$row[0]};
                     #              push (@arr, $val);
                     #         print Dumper @arr;
                     push (@$known{@$row[0]}, $val);
             };
     }
     print "\n";
   }
 }
print Dumper \%known;
请注意,这里没有任何翻译错误,代码的语法看起来是正确的。如果您有关于最后一个push的问题或其他需要修改的部分,请提出具体问题,我将乐意帮助您。另外,您还可以直接将数组分配给散列,而不必生成一个数组并稍后链接其地址。以下是如何直接将数组分配给散列的示例:
my %hash = (
    key1 => [1, 2, 3],  # 直接将数组分配给散列的值
    key2 => [4, 5, 6]
);
# 访问散列中的数组
print @{$hash{key1}};  # 打印数组 [1, 2, 3]
希望这有所帮助!
英文:
I parse a string to HTML and extract tables from it.
The tables have two columns: 1st single (key), 2nd multi-value (values)
I want to store the values in a hash to an arrays.
use strict;
use warnings;
use Data::Dumper qw(Dumper);
my $html='
<p class="auto-cursor-target"><br /></p>
<table class="wrapped">
<colgroup><col style="width: 50.0px;" /><col style="width: 29.0px;" />
</colgroup>
<tbody>
<tr><th><p>Wikispace</p></th><th><p>right</p></th></tr>
<tr><td>mimi</td><td>right1</td></tr>
<tr><td colspan="1">mama</td><td colspan="1">right3,right2</td></tr>
</tbody>
</table>
<p class="auto-cursor-target"><br /></p>
';
use HTML::TableExtract;
my $te = HTML::TableExtract->new( headers => [qw(Wikispace right)] );
$te->parse($html);
my %known;
foreach my $ts ($te->tables) {
   foreach my $row ($ts->rows) {
     print @$row[0], ":::", @$row[1], ":  ";
     foreach my $val (split(/,/,@$row[1])) {
             print $val, ";";
             if (! $known{@$row[0]}) {
               my @arr = ($val);
               @known{@$row[0]}=\@arr;
             } else {
                     # my @arr = \@known{@$row[0]};
                     #              push (@arr, $val);
                     #         print Dumper @arr;
                     push (@$known{@$row[0]}, $val);
             };
     }
     print "\n";
   }
 }
print Dumper \%known;
What am I doing wrong?  What's wrong with the last push, and how would you do it differently?
Also is there no way to assign an array directly to a hash (dictionary) instead of first having to generate an array and later linking its address?
答案1
得分: 2
整体方法是正确的,但存在许多基本错误。我建议首先阅读一些扎实的入门材料,而不是苦苦挣扎于语言的基本概念和语法。
基本错误:$row 是一个数组引用(通常简称为 "arrayref"),所以要提取一个元素,你需要使用 $row->[0];然后,这些元素本身不是数组引用,所以你不能对它们进行解引用(@{ $row->[0] } 是错误的)。还有,你指定的标题是错误的 - 你的文档中没有这样的标题。
我不完全理解整个目的,但这里是经过清理以使其工作的程序示例:
use strict;
use warnings;
use feature 'say';
use Data::Dumper qw(Dumper);
my $html = '<p class="auto-cursor-target"><br /></p><table class="wrapped"><colgroup><col style="width: 50.0px;" /><col style="width: 29.0px;" /></colgroup><tbody><tr><th><p>Wiki    space</p></th><th><p>right</p></th></tr><tr><td>mimi</td><td>right1</td></tr><tr><td colspan="1">mama</td><td colspan="1">right3,right2</td></tr></tbody></table><p class="auto-cursor-target"><br /></p>';
use HTML::TableExtract;
my $te = HTML::TableExtract->new( headers => ['Wiki    space', 'right'] );
$te->parse($html);
my %known;
foreach my $ts ($te->tables) {
    foreach my $row ($ts->rows) {
        foreach my $val ( split /,/, $row->[1] ) {
            print $val, ";";
            if (not $known{$row->[0]}) {
                $known{$row->[0]} = [ $val ];
            }
            else {
                push @{$known{$row->[0]}}, $val;
            };
        }
        say '';
    }
}
print Dumper \%known;
这会输出:
right1;
right3;right2;
$VAR1 = {
          'mimi' => [
                      'right1'
                    ],
          'mama' => [
                      'right3',
                      'right2'
                    ]
        };
英文:
The overall approach is fine but there are many basic errors throughout. I'd suggest to first make a good go over a solid introductory material, instead of suffering with basic notions and syntax of the language.
Basic errors: that $row is an array reference (often called "arrayref" for short) so to extract an element you need $row->[0]; then, those elements themselves are not arrayrefs so you can't dereference them (@{ $row->[0] } is wrong).  And, the headers you specify are wrong -- your document doesn't have such headers.
I don't fully understand the whole purpose but here is youor program cleaned up so that it works
use strict;
use warnings;
use feature 'say';
use Data::Dumper qw(Dumper);
my $html='<p class="auto-cursor-target"><br /></p><table class="wrapped"><colgroup><col style="width: 50.0px;" /><col style="width: 29.0px;" /></colgroup><tbody><tr><th><p>Wiki    space</p></th><th><p>right</p></th></tr><tr><td>mimi</td><td>right1</td></tr><tr><td colspan="1">mama</td><td colspan="1">right3,right2</td></tr></tbody></table><p class="auto-    cursor-target"><br /></p>';
use HTML::TableExtract;
my $te = HTML::TableExtract->new( headers => ['Wiki    space', 'right'] );
$te->parse($html);
my %known;
foreach my $ts ($te->tables) {
    #say "ts: $ts";
    foreach my $row ($ts->rows) {
        #say "row: @{$row}";
        foreach my $val ( split /,/, $row->[1] ) {
            print $val, ";";
            if (not $known{$row->[0]}) {
                $known{$row->[0]} = [ $val ];
            }
            else {
                push @{$known{$row->[0]}}, $val;
            };
        }
        say '';
    }
}
print Dumper \%known;
This prints
right1;
right3;right2;
$VAR1 = {
          'mimi' => [
                      'right1'
                    ],
          'mama' => [
                      'right3',
                      'right2'
                    ]
        };
答案2
得分: 2
请看Perl解引用语法。我们可以看到
@$known{ ... }
等同于
@{ $known }{ ... }
但你没有一个标量 $known。你想要的是
@{ $known{ ... } }
或者
$known{ ... }->@*
这将给我们带来以下代码:
for my $val ( split /,/, $row->[1] ) {
   if ( !$known{ $row->[0] } ) {
      my @arr = $val;                       # 删除了无用的括号。
      @known{ $row->[0] } =  \@arr;
   } else {
      push @{ $known{ $row->[0] } }, $val;
   }                                        # 删除了无用的分号。
}
但让我们清理一下你的代码。
- 
当切片中只有一个元素时,不鼓励使用数组切片。
@{ $row }[0] # 数组切片(通过引用),使用中缀语法应该改为
${ $row }[0] # 数组索引(通过引用),使用中缀语法更清晰的写法是:
$row->[0] # 数组索引(通过引用),使用后缀/箭头语法这将给我们以下代码:
for my $val ( split /,/, $row->[1] ) { if ( !$known{ $row->[0] } ) { my @arr = $val; $known{ $row->[0] } = \@arr; } else { push @{ $known{ $row->[0] } }, $val; } } - 
my @a = ...; \@a可以简化为[ ... ]。这将给我们以下代码:
for my $val ( split /,/, $row->[1] ) { if ( !$known{ $row->[0] } ) { $known{ $row->[0] } = [ $val ]; } else { push @{ $known{ $row->[0] } }, $val; } } - 
我们不需要那个if语句。
for my $val ( split /,/, $row->[1] ) { $known{ $row->[0] } //= []; push @{ $known{ $row->[0] } }, $val; }我们甚至可以合并这两个内部语句。
for my $val ( split /,/, $row->[1] ) { push @{ $known{ $row->[0] } //= [] }, $val; }实际上,借助于自动创建,
@{ EXPR //= [] }可以写成@{ EXPR }。Perl将在需要时自动创建数组。for my $val ( split /,/, $row->[1] ) { push @{ $known{ $row->[0] } }, $val; } - 
你可以一次推送多个值。
这意味着你的整个内部循环可以简化为以下代码:
push @{ $known{ $row->[0] } }, split /,/, $row->[1]; - 
最后,如果第一列是一个键(即唯一值),那么我们根本不需要
push。$known{ $row->[0] } = [ split /,/, $row->[1] ]; 
英文:
See Perl Dereferencing Syntax. We see that
@$known{ ... }
is short for
@{ $known }{ ... }
But you don't have a scalar $known. You want
@{ $known{ ... } }
or
$known{ ... }->@*
This gives us
for my $val ( split /,/, $row->[1] ) {
   if ( !$known{ @$row[0] } ) {
      my @arr = $val;                       # Useless parens removed.
      @known{ @$row[0] } =  \@arr;
   } else {
      push @{ $known{ @$row[0] } }, $val;
   }                                        # Useless `;` removed.
}
But let's clean up your code.
- 
Using an array slice is discouraged when the slice is just one element.
@{ $row }[0] # Array slice (via reference), using infix syntaxshould be
${ $row }[0] # Array index (via reference), using infix syntaxCleaner:
$row->[0] # Array index (via reference), using the postfix/arrow syntaxThis gives us
for my $val ( split /,/, $row->[1] ) { if ( !$known{ $row->[0] } ) { my @arr = $val; $known{ $row->[0] } = \@arr; } else { push @{ $known{ $row->[0] } }, $val; } } - 
my @a = ...; \@acan be shortened to[ ... ].This gives us
for my $val ( split /,/, $row->[1] ) { if ( !$known{ $row->[0] } ) { $known{ $row->[0] } = [ $val ]; } else { push @{ $known{ $row->[0] } }, $val; } } - 
We don't need that if statement.
for my $val ( split /,/, $row->[1] ) { $known{ $row->[0] } //= []; push @{ $known{ $row->[0] } }, $val; }We can even combine those two inner statements.
for my $val ( split /,/, $row->[1] ) { push @{ $known{ $row->[0] } //= [] }, $val; }In fact, thanks to autovivification,
@{ EXPR //= [] }can be written as@{ EXPR }. Perl will automatically create the array if needed.for my $val ( split /,/, $row->[1] ) { push @{ $known{ $row->[0] } }, $val; } - 
You can push multiple values at once.
That means your entire inner loop can be reduced to the following:
push @{ $known{ $row->[0] } }, split /,/, $row->[1]; - 
Finally, if the first column is a key (i.e. unique values), then we don't need
pushat all.$known{ $row->[0] } = [ split /,/, $row->[1] ]; 
答案3
得分: 1
你在这一行上遇到了语法错误:
push (@$known{@$row[0]}, $val);
因为你将变量声明为哈希(%known),但你尝试将其视为标量($known)访问。
以下是一个更简单版本的代码,可以无错误运行:
use strict;
use warnings;
use Data::Dumper qw(Dumper);
my $html = '<p class="auto-cursor-target"><br /></p><table class="wrapped"><colgroup><col style="width: 50.0px;" /><col style="width: 29.0px;" /></colgroup><tbody><tr><th><p>Wikispace</p></th><th><p>right</p></th></tr><tr><td>mimi</td><td>right1</td></tr><tr><td colspan="1">mama</td><td colspan="1">right3,right2</td></tr></tbody></table><p class="auto- cursor-target"><br /></p>';
use HTML::TableExtract;
my $te = HTML::TableExtract->new( headers => [qw(Wikispace right)] );
$te->parse($html);
my %known;
foreach my $ts ($te->tables) {
    foreach my $row (@$ts) {
        my @vals = split(/,/, $row->[1]);
        push(@{$known{$row->[0]}}, @vals);
    }
}
print Dumper(\%known);
输出结果:
$VAR1 = {
          'mama' => [
                      'right3',
                      'right2'
                    ],
          'mimi' => [
                      'right1'
                    ]
        };
英文:
You get a syntax error on the line:
                 push (@$known{@$row[0]}, $val);
because you declared the variable as a hash (%known), but you are trying to access it as a scalar ($known).
Here is a simpler version of your code that runs without errors:
use strict;
use warnings;
use Data::Dumper qw(Dumper);
my $html='<p class="auto-cursor-target"><br /></p><table class="wrapped"><colgroup><col style="width: 50.0px;" /><col style="width: 29.0px;" /></colgroup><tbody><tr><th><p>Wikispace</p></th><th><p>right</p></th></tr><tr><td>mimi</td><td>right1</td></tr><tr><td colspan="1">mama</td><td colspan="1">right3,right2</td></tr></tbody></table><p class="auto-    cursor-target"><br /></p>';
use HTML::TableExtract;
my $te = HTML::TableExtract->new( headers => [qw(Wikispace right)] );
$te->parse($html);
my %known;
foreach my $ts ($te->tables) {
    foreach my $row ($ts->rows) {
        my @vals = split(/,/, $row->[1]);
        $known{ $row->[0] } = [@vals];
    }
 }
print Dumper(\%known);
Output:
$VAR1 = {
          'mama' => [
                      'right3',
                      'right2'
                    ],
          'mimi' => [
                      'right1'
                    ]
        };
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论