Arrays 带循环数组散列的perl散列

Arrays 带循环数组散列的perl散列,arrays,perl,hash,Arrays,Perl,Hash,我在数组散列的散列中有以下数据。数组中的数字数据表示最后四个季度的财务信息 我希望能够遍历数组,并按季度提取数据,以便将其插入数据库。使用下面的代码,我可以得到所有的四分之一,或者只有在我特别调用它的情况下才能得到一个四分之一。当我尝试添加另一个循环来迭代数组散列的散列以只返回数组子集值时,我得到了所有的值,我不知道我做错了什么。请参阅代码:谢谢您的帮助 my %comp_info = ( CompanyA => { COGS => ["175.00", "155.

我在数组散列的散列中有以下数据。数组中的数字数据表示最后四个季度的财务信息

我希望能够遍历数组,并按季度提取数据,以便将其插入数据库。使用下面的代码,我可以得到所有的四分之一,或者只有在我特别调用它的情况下才能得到一个四分之一。当我尝试添加另一个循环来迭代数组散列的散列以只返回数组子集值时,我得到了所有的值,我不知道我做错了什么。请参阅代码:谢谢您的帮助

my %comp_info = (
  CompanyA => {
    COGS    => ["175.00", "155.00", "125.00", "125.00"],
    Revenue => ["300.00", "200.00", "250.00", "225.00"],
  },
)


我强烈建议使用中间变量解除引用,并使用
->
语法。这两种方法都可以帮助您了解发生了什么:

下面是使用解引用的第一个子例程:

sub get_insert_arrays {
    my @insert_array;

    foreach $comp (keys %comp_info ) {      # References to a hash (Revenue, COGS)
        %columns = %{ $comp_info{$comp} };  # Dereference
        foreach $column ( keys %columns ) { # Reference to an Array (quarter data)
            my @values = @{ $column } ;     # Dereference
            push (@insert_array, $column );
            my $valuelist = join(", ", @insert_array);
            &db_insert($valuelist);
        }
    }
}
嗯。。。看到这一点,很容易看出我可以简单地做到:

    for my $comp (keys %comp_info ) {      # References to a hash (Revenue, COGS)
        %columns = %{ $comp_info{$comp} };  # Dereference
        for my $column ( keys %columns ) { # Reference to an Array (quarter data)
            my @values = @{ $column } ;     # Dereference
            db_insert(@values);
        }
    }
}
如果需要查看特定数据段,请使用
->
语法简化结构:

${$comp_info{$sym}{$column}}[$i];   # You had "@". Should be "$".
vs

更容易阅读

还可以在程序中使用
警告
严格
杂注。它将捕获许多错误,可能包括未定义的变量和拼写错误的变量名

如果要逐季度提取数据,您可能希望COGS收入列一起:

#! /usr/bin/env perl
#

use strict;             # Lets you know when you misspell variable names
use warnings;           # Warns of issues (using undefined variables
use feature qw(say);

#
# Just initializing the data you had
#
my %comp_info = ( CompanyA => {
        Revenue => [
            300.00, 200.00, 250.00, 225.00
        ],
        COGS => [
            175.00, 155.00, 125.00, 125.00
        ],
    },
);

#
# Go through each company
#
for my $company ( keys %comp_info ) {
    my @revenues = @{ $comp_info{$company}->{Revenue} };  # Dereference
    my @cogss    = @{ $comp_info{$company}->{COGS} };     # Dereferenec
    say "Company: $company";
    #
    # I know the keys are "Revenue" and "COGS", so I don't need a loop.
    # I'll just go right to my quarters data. Note that dereferencing
    # makes my program a lot easier to write and maintain
    #
    for my $quarter ( (0..3) ) {
        my $revenue = $revenues[$quarter];
        my $cogs    = $cogss[$quarter];
        my $profit = $revenue - $cogs;
        say "    Quarter: " . ($quarter - 1)
             . " Revenue = $revenue  COGS = $cogs Profit = $profit";
    }
}
如何插入数据库取决于您自己。但是,您可以看到,进行一点解引用和使用
->
可以澄清您所看到的内容


补遗 如何只提取季度数据而不必指定收入、COG等。在某些情况下,可能有30多个字段,因此我不想在程序中指定每个字段。我只想抓取所有Q1字段,插入,抓取所有Q2字段,插入,等等

所以有两个循环:

  • 像以前一样,我对每个公司都进行了外部循环,这恰好是
    %comp\u info
    散列的关键
  • %comp_info
    哈希中的每个值都是对另一个哈希的引用,该哈希由数据类型(COGS、Revenue等)键入。同样,我只是循环遍历该内部散列的键(在取消引用以使其更易于理解之后)
  • 现在我有了公司名称(该
    %comp_info
    散列的键,以及该内部散列中的键列表,我可以简单地提取每个公司和每个数据类型的第一季度数字。获取季度值很简单:
    $comp_info{$company}->{$type}->[$quarter]
    。请注意,数据有三个级别,变量中有三个部分,每个部分之间用
    ->
    分隔。
    • 我可以看到最外层的部分是一个简单的散列,由公司名称键入:(
      $comp_info{$company}
    • %comp_info
      哈希指向一个哈希引用(
      ->{type}
      ),该哈希引用由数据类型(COGS、Revenue等)键入
    • 这个散列引用指向每个季度的数组引用(
      ->[$quarter]
      )。看看它是如何工作的,以及我为什么喜欢
      ->
      语法吗?它非常清楚我在使用什么
    • 这只是第一个季度的结果。如果我想每个季度都检查一遍,我可以为我的$quarter(0..3){设置一个外部循环
下面是它的样子。这是一个完整的程序,所以你可以删掉它,试着自己运行它,看看你是否能弄清楚发生了什么

use strict;             # Lets you know when you misspell variable names
use warnings;           # Warns of issues (using undefined variables
use feature qw(say);

my $quarter = 0;        #First Quarter is 0. Last quarter is 3
my %comp_info = ( CompanyA => {
        Revenue => [
            300.00, 200.00, 250.00, 225.00
        ],
        COGS => [
            175.00, 155.00, 125.00, 125.00
        ],
    },
);

for my $company ( keys %comp_info ) {
    say "Company: $company";
    %types = %{ $company_info{$company} };
    for my $type ( keys %types ) {   # COGS, Revenue, etc.
        say "   $type for quarter " 
            . ($quarter + 1) . ": "
            . $comp_info{$company}->{$type}->[$quarter];
    }
}
每季度再插入一次数据到数据库中:

使用
use strict
并使用
my
声明变量意味着变量仅在有限的范围内有效。该
my@type_data;
声明了一个数组,该数组保存我的类型值以插入数据库。但是,由于它是在该
中为我的$quarter
循环声明的,因此该数组及其值在循环的每次迭代中进行搜索。无需删除数据或重新初始化变量。它可以自己完成所有操作

看看你是怎么工作的


您最近添加的-
undef@insert\u array;undef$valuelist;
是对
undef
的滥用。将其放在这样的变量之前会强制执行垃圾收集循环,这是您不想做的事情——最好让Perl自己处理

数组应该用
@insert_array=()
清空,而不是使用
undef
,对于标量,您应该
$valuelist=undef
。但是这些变量在子例程之外是不相关的,所以您应该在里面声明它们,在这种情况下,首先不需要重新初始化它们

请记住我说过的关于在带有占位符的SQL语句上调用
prepare

my $insert = $dbh->prepare('INSERT INTO table VALUES (?, ?)');
后来

my @insert_array = (175.00, 300.00);
$insert->execute(@insert_array);
然而,我写了这篇文章,我认为这是你想要的,就像你自己的代码一样创建一个
$valuelist
字符串。因为你不需要散列键,所以迭代这些值要整洁得多。
db_insert
子例程是一个伪例程,它只打印传递给它的参数值

use strict;
use warnings;
use 5.010;

my %comp_info = (
  CompanyA => {
    COGS    => ["175.00", "155.00", "125.00", "125.00"],
    Revenue => ["300.00", "200.00", "250.00", "225.00"],
  },
);

my @values = map values %$_, values %comp_info;

for my $i (0 .. $#{$values[0]}) {
  my @insert = map $_->[$i], @values;
  db_insert(join ', ', @insert);
}

sub db_insert {
  say "db_insert('@_')";
}
输出

db_insert('175.00, 300.00')
db_insert('155.00, 200.00')
db_insert('125.00, 250.00')
db_insert('125.00, 225.00')
db_insert('CompanyC, 175.00, 300.00')
db_insert('CompanyC, 155.00, 200.00')
db_insert('CompanyC, 125.00, 250.00')
db_insert('CompanyC, 125.00, 225.00')
db_insert('CompanyA, 175.00, 300.00')
db_insert('CompanyA, 155.00, 200.00')
db_insert('CompanyA, 125.00, 250.00')
db_insert('CompanyA, 125.00, 225.00')
db_insert('CompanyB, 175.00, 300.00')
db_insert('CompanyB, 155.00, 200.00')
db_insert('CompanyB, 125.00, 250.00')
db_insert('CompanyB, 125.00, 225.00')

更新

要符合新规范,请执行以下操作:

use strict;
use warnings;
use 5.010;

my %comp_info = (
  CompanyA => {
    COGS    => ["175.00", "155.00", "125.00", "125.00"],
    Revenue => ["300.00", "200.00", "250.00", "225.00"],
  },
  CompanyB => {
    COGS    => ["175.00", "155.00", "125.00", "125.00"],
    Revenue => ["300.00", "200.00", "250.00", "225.00"],
  },
  CompanyC => {
    COGS    => ["175.00", "155.00", "125.00", "125.00"],
    Revenue => ["300.00", "200.00", "250.00", "225.00"],
  },
);

my @columns = qw/ COGS Revenue /;

for my $comp (keys %comp_info) {
  my $data = $comp_info{$comp};
  for my $i (0 .. $#{(values %$data)[0]}) {
    my @values = ( $comp, map $_->[$i], @{$data}{@columns} );
    db_insert(join ', ', @values);
  }
}

sub db_insert {
  say "db_insert('@_')";
}
输出

db_insert('175.00, 300.00')
db_insert('155.00, 200.00')
db_insert('125.00, 250.00')
db_insert('125.00, 225.00')
db_insert('CompanyC, 175.00, 300.00')
db_insert('CompanyC, 155.00, 200.00')
db_insert('CompanyC, 125.00, 250.00')
db_insert('CompanyC, 125.00, 225.00')
db_insert('CompanyA, 175.00, 300.00')
db_insert('CompanyA, 155.00, 200.00')
db_insert('CompanyA, 125.00, 250.00')
db_insert('CompanyA, 125.00, 225.00')
db_insert('CompanyB, 175.00, 300.00')
db_insert('CompanyB, 155.00, 200.00')
db_insert('CompanyB, 125.00, 250.00')
db_insert('CompanyB, 125.00, 225.00')

不清楚您想要什么。您的第一个示例获得了所有第一季度的数字,而第二个示例提供了所有的数字。我不知道还有什么其他选项。顺便说一下,您应该
准备
一个使用占位符的SQL语句,并将值传递到
execute
,而不是构建我想知道,我是否能够以这样的方式构造它,以生成一个循环,该循环将给出第一个四分之一的数字,我将其传递到db_insert中,然后是第二个qu
use strict;
use warnings;
use 5.010;

my %comp_info = (
  CompanyA => {
    COGS    => ["175.00", "155.00", "125.00", "125.00"],
    Revenue => ["300.00", "200.00", "250.00", "225.00"],
  },
  CompanyB => {
    COGS    => ["175.00", "155.00", "125.00", "125.00"],
    Revenue => ["300.00", "200.00", "250.00", "225.00"],
  },
  CompanyC => {
    COGS    => ["175.00", "155.00", "125.00", "125.00"],
    Revenue => ["300.00", "200.00", "250.00", "225.00"],
  },
);

my @columns = qw/ COGS Revenue /;

for my $comp (keys %comp_info) {
  my $data = $comp_info{$comp};
  for my $i (0 .. $#{(values %$data)[0]}) {
    my @values = ( $comp, map $_->[$i], @{$data}{@columns} );
    db_insert(join ', ', @values);
  }
}

sub db_insert {
  say "db_insert('@_')";
}
db_insert('CompanyC, 175.00, 300.00')
db_insert('CompanyC, 155.00, 200.00')
db_insert('CompanyC, 125.00, 250.00')
db_insert('CompanyC, 125.00, 225.00')
db_insert('CompanyA, 175.00, 300.00')
db_insert('CompanyA, 155.00, 200.00')
db_insert('CompanyA, 125.00, 250.00')
db_insert('CompanyA, 125.00, 225.00')
db_insert('CompanyB, 175.00, 300.00')
db_insert('CompanyB, 155.00, 200.00')
db_insert('CompanyB, 125.00, 250.00')
db_insert('CompanyB, 125.00, 225.00')