哈希的键作为数组,匹配后将键值放入数组中

huangapple go评论58阅读模式
英文:

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= &quot;./file.txt&quot;;	

die &quot;cannot open csv\n&quot; if (!open(CSV, &quot;&lt;$csv&quot; ));

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 (&lt;CSV&gt;){
	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 &quot;Line-----$bil,,,, $v\n&quot;;
		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&#39;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 &quot;School&quot; and &quot;College&quot; 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 &quot;@&quot;. That&#39;s simple enough to do:

    foreach (keys %data) {
      say &#39;@&#39;, $_;
    }

It might be tempting to put that into a double-quoted string (`&quot;@$_&quot;`) but Perl would then interpret the &quot;@&quot; as the start of an array variable (which it isn&#39;t here). So the simplest fix is to split the string into two parts.

We then want the string to have &quot;=(STUFF)&quot; - so let&#39;s add that.

    foreach (keys %data) {
      say &#39;@&#39;, &quot;$_ = (STUFF)&quot;
    }
Of course, &quot;STUFF&quot; is a bit more complicated. We can start by printing the value from the hash:

    foreach (keys %data) {
      say &#39;@&#39;, &quot;$_ = ($data{$_})&quot;
    }

But that doesn&#39;t give us what we want:

    @College = (ARRAY(0x55c35f9c8fd0))
    @University = (ARRAY(0x55c35f9c8e68))
    @School = (ARRAY(0x55c35f9d23e8))

That&#39;s because what we have is an array *reference*. So we need to dereference it.

    for (keys %data) {
      say &#39;@&#39;, &quot;$_ = (@{$data{$_}})&quot;
    }
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&#39;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 &#39;@&#39;,
          &quot;$_ = (&quot;,
          join(&#39;, &#39;, @{$data{$_}}),
          &#39;)&#39;
    }
We&#39;re printing four sections here:

1. The initial &quot;@&quot;
1. The key name (in `$_`) along with the next, fixed parts of the string
1. A string we generate from calling `join()` passing it &quot;, &quot; and our dereferenced array
1. A closing &quot;)&quot; 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&#39;s simpler and more flexible to just read the data from the command line. That&#39;s what

    while (&lt;&gt;) {
      ...
    }

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 &#39;say&#39;;

# Where we&#39;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 (&lt;&gt;) {
  # This looks for the array name record, extracts the
  # string from between &quot;Type&quot; and &quot;Authors&quot; and stores that
  # string as $key
  if (/Type:,(\w+),Authors:/) {
    $key = $1;
  }

  # This looks for &quot;STRING&quot; 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 &#39;@&#39;, &quot;$_ = (&quot;, join(&#39;, &#39;, @{$data{$_}}), &#39;)&#39;;
}

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 &#39;@&#39;, $_;
}

It might be tempting to put that into a double-quoted string (&quot;@$_&quot;) 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 &#39;@&#39;, &quot;$_ = (STUFF)&quot;;
}

Of course, "STUFF" is a bit more complicated. We can start by printing the value from the hash:

foreach (keys %data) {
  say &#39;@&#39;, &quot;$_ = ($data{$_})&quot;;
}

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 &#39;@&#39;, &quot;$_ = (@{$data{$_}})&quot;;
}

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 &#39;@&#39;,
      &quot;$_ = (&quot;,
      join(&#39;, &#39;, @{$data{$_}}),
      &#39;)&#39;;
}

We're printing four sections here:

  1. The initial "@"
  2. The key name (in $_) along with the next, fixed parts of the string
  3. A string we generate from calling join() passing it ", " and our dereferenced array
  4. 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 (&lt;&gt;) {
  ...
}

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= &quot;./file.txt&quot;;

open(CSV, &quot;&lt;&quot;, $csv )
    or die &quot;cannot open csv\n&quot;;

my %storage;
my $compiler;

my %bil = map { $_ =&gt; 1}
          qw(
            STRING_a
            STRING_b
            STRING_c
            STRING_d
            STRING_e
            STRING_f
            STRING_x
            STRING_y
            STRING_z
            STRING_k
        );

while (&lt;CSV&gt;){
    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 &quot;school     [@school]&quot;;
say &quot;University [@University]&quot;;
say &quot;College    [@College]&quot;;

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= &quot;./file.txt&quot;;

open(CSV, &quot;&lt;&quot;, $csv )
    or die &quot;cannot open csv\n&quot;;

my %storage;
my $compiler;
my @compilers;

my %bil = map { $_ =&gt; 1}
          qw(
            STRING_a
            STRING_b
            STRING_c
            STRING_d
            STRING_e
            STRING_f
            STRING_x
            STRING_y
            STRING_z
            STRING_k
        );

while (&lt;CSV&gt;){
    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 = {
          &#39;University&#39; =&gt; [
                            &#39;STRING_a&#39;,
                            &#39;STRING_b&#39;,
                            &#39;STRING_c&#39;
                          ],
          &#39;School&#39; =&gt; [
                        &#39;STRING_x&#39;,
                        &#39;STRING_y&#39;,
                        &#39;STRING_z&#39;,
                        &#39;STRING_k&#39;
                      ],
          &#39;College&#39; =&gt; [
                         &#39;STRING_d&#39;,
                         &#39;STRING_e&#39;,
                         &#39;STRING_f&#39;
                       ]
        };

huangapple
  • 本文由 发表于 2023年2月27日 15:52:16
  • 转载请务必保留本文链接:https://go.coder-hub.com/75577938.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定