英文:
Keys of hash as arrays and keys values into arrays after match
问题
以下是代码部分的翻译:
#!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper;
use feature qw(say);
my $csv = "./file.txt";
die "无法打开 CSV 文件\n" if (!open(CSV, "<$csv"));
my %storage;
my $compiler;
my $macro;
my @bil = qw(
STRING_a STRING_b STRING_c STRING_d STRING_e
STRING_f STRING_x STRING_y STRING_z STRING_k
);
while (<CSV>) {
chomp(my $line = $_);
next if ($line !~ /^No|^\d+/ );
$compiler = $1 if ($line =~ /No,\d+,Type:,(\w+)/);
if ($line =~ /\d+,\d+,\d+,(\w+),/) {
$macro = $1;
push @{$storage{$compiler}}, $1;
}
}
close CSV;
print Dumper \%storage;
for my $bil (@bil) {
while (my ($k, $v) = each %storage) {
print "行-----$bil,,,, $v\n";
if ($bil =~ $v) {
#需要帮助(我想将 $v 存储到一个名为 $k 的数组中)
}
}
}
请注意,代码中的注释(#需要帮助...)是需要进一步处理的部分,用于将值存储到相应的数组中。如果您需要进一步的解释或帮助,可以提出具体的问题。
英文:
I have given shown file as input to script and created an hash. I want to make keys as arrays and the corresponding key values into that array after the match.
I have created hash, but finding issues to create keys as arrays and its values into the corresponding array. Any help is highly appreciated.
Expected output is as below
@school = (STRING_x, STRING_y, STRING_z,STRING_k)
@University = (STRING_a, STRING_b, STRING_c)s
@College = (STRING_d, STRING_e, STRING_f)
Input file
begin_
No,59,Type:,School,Authors:,,,,
Local,config
0,0,0,STRING_x,256
1,0,1,STRING_y,256
2,0,2,STRING_z,256
3,0,3,STRING_k,256
end,,,,,
begin_
No,99,Type:,University,Authors:,,,
Local,config
0,0,0,STRING_a,64
0,0,0,STRING_b,64
0,0,0,STRING_c,64
end,,,,,
begin_
No,234,Type:,College,Authors:,,,
Local,config
0,0,0,STRING_d,32
0,0,0,STRING_e,32
0,0,0,STRING_f,32
end,,,,,
#!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper;
use feature qw(say);
my $csv= "./file.txt";
die "cannot open csv\n" if (!open(CSV, "<$csv" ));
my %storage;
my $compiler;
my $macro;
my @bil = qw(
STRING_a STRING_b STRING_c STRING_d STRING_e
STRING_f STRING_x STRING_y STRING_z STRING_k
);
while (<CSV>){
chomp(my $line =$_);
next if ($line !~ /^No|^\d+/ );
$compiler = $1 if ($line =~ /No,\d+,Type:,(\w+)/);
if ($line =~ /\d+,\d+,\d+,(\w+),/){
$macro=$1;
push @{$storage{$compiler}},$1;
}
}
close CSV;
print Dumper \%storage;
for my $bil(@bil) {
while (my ($k,$v) =each%storage ){
print "Line-----$bil,,,, $v\n";
if ($bil =~$v){
#Need help (I want to store the $v into an array having the name $k)
}
}
}
答案1
得分: 3
以下是翻译好的部分,代码部分未翻译:
Something like this, perhaps. It processes the file in two stages.
Stage 1 parses the input data, extracting the information that is useful to us and stores it in a hash. The keys of the hash are array names and the values in the hash are array references containing the elements of the array.
Stage 2 walks the has we built in stage 1 and turns it into the required output.
**Update:** Ok, let's look at the final loop in a bit more detail.
We have a hash, called `%data` that contains information that we have parsed from the input file. The keys are things like "School" and "College" and the values are an array reference.
We start by looping over the keys of that hash. We could just print those keys.
foreach (keys %data) {
say $_;
}
Note that each time we go round this loop, the variable `$_` contains one of the keys from the hash. Because hashes are sorted randomly, we get those keys back in a random order each time.
You want the key name to be preceded by an "@". That's simple enough to do:
foreach (keys %data) {
say '@', $_;
}
It might be tempting to put that into a double-quoted string (`"@$_"`) but Perl would then interpret the "@" as the start of an array variable (which it isn't here). So the simplest fix is to split the string into two parts.
We then want the string to have "=(STUFF)" - so let's add that.
foreach (keys %data) {
say '@', "$_ = (STUFF)"
}
Of course, "STUFF" is a bit more complicated. We can start by printing the value from the hash:
foreach (keys %data) {
say '@', "$_ = ($data{$_})"
}
But that doesn't give us what we want:
@College = (ARRAY(0x55c35f9c8fd0))
@University = (ARRAY(0x55c35f9c8e68))
@School = (ARRAY(0x55c35f9d23e8))
That's because what we have is an array *reference*. So we need to dereference it.
for (keys %data) {
say '@', "$_ = (@{$data{$_}})"
}
That gets us closer:
@University = (STRING_a STRING_b STRING_c)
@School = (STRING_x STRING_y STRING_z STRING_k)
@College = (STRING_d STRING_e STRING_f)
But you asked for commas between the elements in the list. We can do that using `join()`, but we need to split apart the bits of the output string - as you can't call functions inside a string. It might be easier to understand if we put each part of the output string on a separate line:
for (keys %data) {
say '@',
"$_ = (",
join(', ', @{$data{$_}}),
')'
}
We're printing four sections here:
1. The initial "@"
1. The key name (in `$_`) along with the next, fixed parts of the string
1. A string we generate from calling `join()` passing it ", " and our dereferenced array
1. A closing ")" for the end of our list
Putting these all together, gives us this output:
@College = (STRING_d, STRING_e, STRING_f)
@School = (STRING_x, STRING_y, STRING_z, STRING_k)
@University = (STRING_a, STRING_b, STRING_c)
One thing I forgot to mention is that I got rid of your code that hardcoded the input file name and opened the file. It's simpler and more flexible to just read the data from the command line. That's what
while (<>) {
...
}
does. It just reads data from filenames that are passed on the command line and puts each line in turn into `$_`.
I hope that makes things clearer.
希望对你有所帮助。
英文:
Something like this, perhaps. It processes the file in two stages.
Stage 1 parses the input data, extracting the information that is useful to us and stores it in a hash. The keys of the hash are array names and the values in the hash are array references containing the elements of the array.
Stage 2 walks the has we built in stage 1 and turns it into the required output.
#!/usr/bin/perl
use strict;
use warnings;
use feature 'say';
# Where we're going to store the useful bits of the
# data during the parsing stage
my %data;
# Where we store the name of the current hash key.
my $key;
# Stage 1: Parsing
while (<>) {
# This looks for the array name record, extracts the
# string from between "Type" and "Authors" and stores that
# string as $key
if (/Type:,(\w+),Authors:/) {
$key = $1;
}
# This looks for "STRING" record, extracts that from the input
# line and pushes that onto the end of the current array reference
if (/(STRING[^,]+)/) {
push @{$data{$key}}, $1;
}
}
# Stage 2: Output
# For each key in the data hash...
for (keys %data) {
# ... extract the data we want and print it
say '@', "$_ = (", join(', ', @{$data{$_}}), ')';
}
Update: Ok, let's look at the final loop in a bit more detail.
We have a hash, called %data
that contains information that we have parsed from the input file. The keys are things like "School" and "College" and the values are an array reference.
We start by looping over the keys of that hash. We could just print those keys.
foreach (keys %data) {
say $_;
}
Note that each time we go round this loop, the variable $_
contains one of the keys from the hash. Because hashes are sorted randomly, we get those keys back in a random order each time.
You want the key name to be preceded by an "@". That's simple enough to do:
foreach (keys %data) {
say '@', $_;
}
It might be tempting to put that into a double-quoted string ("@$_"
) but Perl would then interpret the "@" as the start of an array variable (which it isn't here). So the simplest fix is to split the string into two parts.
We then want the string to have "=(STUFF)" - so let's add that.
foreach (keys %data) {
say '@', "$_ = (STUFF)";
}
Of course, "STUFF" is a bit more complicated. We can start by printing the value from the hash:
foreach (keys %data) {
say '@', "$_ = ($data{$_})";
}
But that doesn't give us what we want:
@College = (ARRAY(0x55c35f9c8fd0))
@University = (ARRAY(0x55c35f9c8e68))
@School = (ARRAY(0x55c35f9d23e8))
That's because what we have is an array reference. So we need to dereference it.
for (keys %data) {
say '@', "$_ = (@{$data{$_}})";
}
That gets us closer:
@University = (STRING_a STRING_b STRING_c)
@School = (STRING_x STRING_y STRING_z STRING_k)
@College = (STRING_d STRING_e STRING_f)
But you asked for commas between the elements in the list. We can do that using join()
, but we need to split apart the bits of the output string - as you can't call functions inside a string. It might be easier to understand if we put each part of the output string on a separate line:
for (keys %data) {
say '@',
"$_ = (",
join(', ', @{$data{$_}}),
')';
}
We're printing four sections here:
- The initial "@"
- The key name (in
$_
) along with the next, fixed parts of the string - A string we generate from calling
join()
passing it ", " and our dereferenced array - A closing ")" for the end of our list
Putting these all together, gives us this output:
@College = (STRING_d, STRING_e, STRING_f)
@School = (STRING_x, STRING_y, STRING_z, STRING_k)
@University = (STRING_a, STRING_b, STRING_c)
One thing I forgot to mention is that I got rid of your code that hardcoded the input file name and opened the file. It's simpler and more flexible to just read the data from the command line. That's what
while (<>) {
...
}
does. It just reads data from filenames that are passed on the command line and puts each line in turn into $_
.
I hope that makes things clearer.
答案2
得分: 2
以下是您的代码的重新组织版本:
#!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper;
use feature qw(say);
my $csv = "./file.txt";
open(CSV, "<", $csv)
or die "无法打开 CSV 文件\n";
my %storage;
my $compiler;
my %bil = map { $_ => 1 }
qw(
STRING_a
STRING_b
STRING_c
STRING_d
STRING_e
STRING_f
STRING_x
STRING_y
STRING_z
STRING_k
);
while (<CSV>) {
chomp(my $line = $_);
next
if $line !~ /^No|^\d+/;
$compiler = $1
if ($line =~ /No,\d+,Type:(\w+)/);
if ($line =~ /\d+,\d+,\d+,(\w+),/) {
my $macro = $1;
push @{$storage{$compiler}}, $1;
}
}
close CSV;
my @school = grep { $bil{$_} } @{$storage{School}};
my @University = grep { $bil{$_} } @{$storage{University}};
my @College = grep { $bil{$_} } @{$storage{College}};
say "school [@school]";
say "University [@University]";
say "College [@College]";
运行代码会输出以下结果:
school [STRING_x STRING_y STRING_z STRING_k]
University [STRING_a STRING_b STRING_c]
College [STRING_d STRING_e STRING_f]
如果完整的compilers
列表(即 School、University、College)仅在file.txt
中可用,您可以修改代码如下,以创建一个存储每个compiler
数据的results
哈希表:
#!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper;
use feature qw(say);
my $csv = "./file.txt";
open(CSV, "<", $csv)
or die "无法打开 CSV 文件\n";
my %storage;
my $compiler;
my @compilers;
my %bil = map { $_ => 1 }
qw(
STRING_a
STRING_b
STRING_c
STRING_d
STRING_e
STRING_f
STRING_x
STRING_y
STRING_z
STRING_k
);
while (<CSV>) {
chomp(my $line = $_);
next
if $line !~ /^No|^\d+/;
if ($line =~ /No,\d+,Type:(\w+)/) {
$compiler = $1;
push @compilers, $compiler;
}
if ($line =~ /\d+,\d+,\d+,(\w+),/) {
my $macro = $1;
push @{$storage{$compiler}}, $1;
}
}
close CSV;
my %results;
for my $comp (@compilers) {
@{$results{$comp}} = grep { $bil{$_} } @{$storage{$comp}};
}
say Dumper \%results;
输出如下:
$VAR1 = {
'University' => [
'STRING_a',
'STRING_b',
'STRING_c'
],
'School' => [
'STRING_x',
'STRING_y',
'STRING_z',
'STRING_k'
],
'College' => [
'STRING_d',
'STRING_e',
'STRING_f'
]
};
英文:
Below is a restructured version of your code.
#!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper;
use feature qw(say);
my $csv= "./file.txt";
open(CSV, "<", $csv )
or die "cannot open csv\n";
my %storage;
my $compiler;
my %bil = map { $_ => 1}
qw(
STRING_a
STRING_b
STRING_c
STRING_d
STRING_e
STRING_f
STRING_x
STRING_y
STRING_z
STRING_k
);
while (<CSV>){
chomp(my $line = $_);
next
if $line !~ /^No|^\d+/ ;
$compiler = $1
if ($line =~ /No,\d+,Type:,(\w+)/);
if ($line =~ /\d+,\d+,\d+,(\w+),/){
my $macro = $1;
push @{ $storage{$compiler} }, $1;
}
}
close CSV;
# print Dumper \%storage;
my @school = grep { $bil{$_} } @{ $storage{School} } ;
my @University = grep { $bil{$_} } @{ $storage{University} } ;
my @College = grep { $bil{$_} } @{ $storage{College} } ;
say "school [@school]";
say "University [@University]";
say "College [@College]";
running gives this output
school [STRING_x STRING_y STRING_z STRING_k]
University [STRING_a STRING_b STRING_c]
College [STRING_d STRING_e STRING_f]
If the full list of compilers
, (i.e. School, University, College) is only available in file.txt
, you can modify the code as follows to get it to create a results
hash that stores the data for each of the compilers
#!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper;
use feature qw(say);
my $csv= "./file.txt";
open(CSV, "<", $csv )
or die "cannot open csv\n";
my %storage;
my $compiler;
my @compilers;
my %bil = map { $_ => 1}
qw(
STRING_a
STRING_b
STRING_c
STRING_d
STRING_e
STRING_f
STRING_x
STRING_y
STRING_z
STRING_k
);
while (<CSV>){
chomp(my $line = $_);
next
if $line !~ /^No|^\d+/ ;
if ($line =~ /No,\d+,Type:,(\w+)/) {
$compiler = $1 ;
push @compilers, $compiler;
}
if ($line =~ /\d+,\d+,\d+,(\w+),/){
my $macro = $1;
push @{ $storage{$compiler} }, $1;
}
}
close CSV;
my %results ;
for my $comp (@compilers)
{
@{ $results{$comp} } = grep { $bil{$_} } @{ $storage{$comp} } ;
}
say Dumper \%results;
output is
$VAR1 = {
'University' => [
'STRING_a',
'STRING_b',
'STRING_c'
],
'School' => [
'STRING_x',
'STRING_y',
'STRING_z',
'STRING_k'
],
'College' => [
'STRING_d',
'STRING_e',
'STRING_f'
]
};
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论