如何将Perl散列哈希转换为更灵活的数据结构?

时间:2009-07-25 16:40:09

标签: perl data-structures oop

在一个快速而又脏的Perl脚本中,我有一个这样的数据结构:

$tax_revenue{YEAR}{STATE}{GOVLEV}{TAX} = integer

哈希键假定这样的值:

YEAR: 1900 .. 2000
STATE: AK, AL, ... WY
GOVLEV: state, local
TAX: type of tax (income, sales, etc.)

此外,哈希键是唯一的。例如,TAX参数的值不会与另一个其他参数的值冲突。

我正在开始使用这些数据的中型项目,我希望以更灵活的方式实现数据结构。我不知道我还需要的所有数据检索功能,但这里有一些例子:

# Specify the parameters in any order.
Tax_rev( qw(1902 WY state property) );
Tax_rev( qw(state property 1902 WY) );

# Use named parameters.
Tax_rev(year => 1902, state => 'WY', govlev => 'state', tax => 'property');

# Use wildcards to obtain a list of values.
# For example, state property tax revenue in 1902 for all states.
Tax_rev( qw(1902 * state property) );

我最初的倾向是继续将数据存储为散列哈希,并构建一个或多个实用程序函数(可能作为类的一部分)来检索值。但后来我想知道是否有更好的策略 - 存储除散列哈希之外的基础数据的某种方式。任何关于如何处理这个问题的建议都将不胜感激。

5 个答案:

答案 0 :(得分:6)

请考虑将数据放入SQLite数据库。然后,您可以灵活地运行您想要的任何查询(通过DBI或只是SQL的命令行界面),并获得适合于通过州或州的税收或税收为所有人生成税收报告的数据结构名称以字母'W'等开头的状态等我假设数据已经是某种字符分隔格式(制表符,逗号,管道等),因此可以轻松地批量导入到SQLite数据库中,节省了一些工作和这方面的代码。

答案 1 :(得分:3)

如果你想要一个纯粹的Perl实现,你可以构建一个哈希数组:

my @taxdata = (
    { year => 1902, state => 'WY', level => 'state', type => 'property', amount => 500 },
    # ...
);

my @matches = grep {
    $_->{year}  == 1902    &&
    $_->{level} eq 'state' &&
    $_->{type}  eq 'property'
} @taxdata;

如果你想对它运行任意查询,那就很灵活了,但如果你想能够获得特定记录,那就很慢。

更好的解决方案可能是具有单个表的数据库,其中每行包含您列出的字段。然后,您可以编写SQL查询以根据任意条件提取数据。您可以使用DBI模块来处理连接。

答案 2 :(得分:1)

我建议你研究一下像Moose这样的对象系统。学习曲线不是太陡(或根本没有陡峭),其好处将是巨大的。你可以从以下内容开始:

package MyApp;

use Moose; # use strict automagically in effect

has 'year'   => ( is => 'ro', isa => 'Int', required => 1 );
has 'state'  => ( is => 'ro', isa => 'Str', required => 1 );
has 'govlev' => ( is => 'ro', isa => 'Str', required => 1 );
has 'tax'    => ( is => 'ro', isa => 'Str', required => 1 );

然后在你的主程序中:

use MyApp;

my $obj = MyApp->new(
    year   => 2000,
    state  => 'AK',
    govlev => 'local',
    tax    => 'revenue'
);

# ...

借助MooseX :: Types的灵活性,您可以继续使用枚举等声明自己的类型类。

一旦你去了Moose,你永远不会回头:)

答案 3 :(得分:1)

查看Data::Diver:“对深层嵌套结构元素的简单,临时访问”。它似乎完全符合您的要求Tax_rev

use Data::Diver qw( Dive );

...
$tax_revenue{ 1900 }{ NC }{ STATE }{ SALES } = 1000;
...

  Dive( \%Hash, qw( 1900 NC STATE SALES ) ) => 1000;
  Dive( \%Hash, qw( 1901 NC STATE SALES ) ) => undef;

答案 4 :(得分:0)

如果您不打算使用对象,我认为数据结构可以正常工作。

以下是Tax_rev()的示例。它不是全功能,但你可以按任意顺序给它4个参数。如果你真的使用它,你可能想检查输入。

my $result = Tax_rev( \%data, qw(state property 1902 WY) );

use strict;
use warnings;
use 5.010;