简体   繁体   English

在Perl中将哈希值用作类别

[英]Using hash values as categories in Perl

I'm reading two tab separated files into two hashes, files looks like this: 我正在将两个制表符分隔的文件读入两个哈希,文件看起来像这样:

apple fruit
pear  fruit
carrot vegetable
potato vegetable
peach fruit

and

apple 23
pear  34
carrot 12
potato 45
peach 12

I want to pick up only vegetable and get their numbers. 我只想捡蔬菜并得到他们的数量。 Is there any smarter way than through the for cycle to do this? 有没有比for循环更智能的方法呢? And if I want to create two new hashes %fruits and %vegetable, do I really have to do it like: 而且,如果我想创建两个新的哈希值%fruits和%vegetable,我是否真的必须这样做:

foreach (keys %kinds_hash) {
   if ($kinds_hash{$_} =~ "vegetable") {
      $vegetable{$_} = $numbers_hash{$_};
   } elsif ($kinds_hash{$_} =~ "fruit") {
      $fruit{$_} = $numbers_hash{$_};
   }
}

There's nothing wrong with iterating on all the values. 遍历所有值没有错。

However, if you're going to be doing it often, then perhaps it would be useful to create a new data structure that contains an array of names based off type. 但是,如果您要经常这样做,那么创建包含基于类型的名称数组的新数据结构也许会很有用。

use strict;
use warnings;

# Data in Paragraph mode
local $/ = '';

my %counts = split ' ', <DATA>;
my %types = split ' ', <DATA>;

# Create a structure that puts each type into an array
my %group_by_type;
while (my ($name, $type) = each %types) {
    push @{$group_by_type{$type}}, $name
}

# Show all Veges
for my $fruit (@{$group_by_type{vegetable}}) {
    print "$fruit $counts{$fruit}\n";
}

__DATA__
apple 23
pear 34
carrot 12
potato 45
peach 12

apple fruit
pear fruit
carrot vegetable
potato vegetable
peach fruit

Outputs: 输出:

carrot 12
potato 45

To learn more about Hashes of Arrays and other data structures, check out perldsc - Perl Data Structures Cookbook 要了解有关数组哈希和其他数据结构的更多信息,请查看perldsc -Perl数据结构食谱

You should structure your data so that all the ways you want to access it are made as simple as possible. 您应该对数据进行结构设计,以便尽可能简化所有想要访问数据的方式。

You want to access all the items in the vegetable category, and the numbers for all of those items. 您要访问vegetable类别中的所有项目以及所有这些项目的编号。 To make that simple I would build two hashes - one relating the names of the items to their number and category, and another relating the categories to all the names in each category. 为简单起见,我将构建两个哈希值-一个将项目名称与它们的编号和类别相关联,另一个将类别与每个类别中的所有名称相关联。

This code does just that and uses Data::Dump to show you what has been built. 这段代码就是这样做的,并使用Data::Dump向您展示已构建的内容。

use strict;
use warnings;
use autodie;

my %items;
my %categories;

open my $fh, '<', 'numbers.tabsep';
while (<$fh>) {
  next unless /\S/;
  chomp;
  my ($name, $number) = split /\t/;
  $items{$name}[0] = $number;
}

open $fh, '<', 'categories.tabsep';
while (<$fh>) {
  next unless /\S/;
  chomp;
  my ($name, $cat) = split /\t/;
  $items{$name}[1] = $cat;
  push @{ $categories{$cat} }, $name;
}

use Data::Dump;
dd \%items;
dd \%categories;

output 输出

{
  apple  => [23, "fruit"],
  carrot => [12, "vegetable"],
  peach  => [12, "fruit"],
  pear   => [34, "fruit"],
  potato => [45, "vegetable"],
}
{
  fruit => ["apple", "pear", "peach"],
  vegetable => ["carrot", "potato"],
}

Now, to answer the question "I want to pick up only vegetables and get their numbers" we just loop over the vegetable element of the %categories hash, and use the %items hash to determine their numbers. 现在,要回答“我只想拿起蔬菜并获取它们的数量”的问题,我们只需要循环遍历%categories哈希值的vegetable元素,然后使用%items哈希值来确定其数量。 Like this 像这样

for my $item (@{ $categories{vegetable} }) {
  printf "%s %d\n", $item, $items{$item}[0];
}

output 输出

carrot 12
potato 45

Tool completed successfully 工具成功完成

You can create hash of hashes, just one nested data structure where the inner key will be your category and the value will be another hash whose key will be type and value be the number. 您可以创建哈希的哈希,只有一个嵌套的数据结构,其中内部键将是您的类别,值将是另一个哈希,其键将是type,而value是数字。

Following program does that: 以下程序可以做到这一点:

#!/usr/bin/perl

use strict;
use warnings;
use Data::Dumper;

my %data; 

open my $fh_one, '<', 'file1';
while(<$fh_one>) {
    next unless /\S+/;
    chomp;
    my ($type, $category) = split /\t/;
    $data{$category}{$type} = undef;
}
close($fh_one);

open my $fh_two, '<', 'file2';
OUTER: while(<$fh_two>) {
    next unless /\S+/;
    chomp;
    my ($type, $number) = split /\t/;
    for my $category (keys %data) {
        for my $item (keys %{ $data{$category} }) {
            $data{$category}{$item} = $number and next OUTER if $item eq $type;
        }
    }
}
close($fh_two);

#print Dumper \%data;

while (my ($type, $number) = each $data{'vegetable'}) {
    print "$type $number\n";
}

If you uncomment the print Dumper \\%data; 如果取消注释print Dumper \\%data; you will see the nested data structure. 您将看到嵌套的数据结构。 It will look like the following: 它将如下所示:

$VAR1 = {
          'fruit' => {
                       'peach' => '12',
                       'apple' => '23',
                       'pear' => '34'
                     },
          'vegetable' => {
                           'carrot' => '12',
                           'potato' => '45'
                         }
        };

The output of the above program is: 上面程序的输出是:

carrot 12
potato 45

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM