使用变量名作为哈希中的键名(Perl)

时间:2013-08-23 17:20:43

标签: perl

我想要简化这个Perl代码块。它是子例程的一部分,其中一系列参数被添加到散列哈希值中。

$user{$account_num}{'item0'} += $item0;
$user{$account_num}{'item1'} += $item1;
$user{$account_num}{'item2'} += $item2;
$user{$account_num}{'item3'} += $item3;
$user{$account_num}{'item4'} += $item4;
$user{$account_num}{'item5'} += $item5;
$user{$account_num}{'item6'} += $item6;

您可以看到变量名称与键名称相同。我好像记得看过一个朋友一次做这种事。类似的东西:

[looping through input arguments]:
$user{$account_num}{'variable_name'} += $variable_name;

有人知道这样做的方法吗?

6 个答案:

答案 0 :(得分:4)

语法是

for my $i (0..6) {
   my $variable_name = "item$i";
   $user{$account_num}{$variable_name} += $$variable_name;
}

但它假设$item0,这是包变量,它使用goes against软件开发的基本原则。


您应该使用数组。

$user{$account_num}{'item0'} += $items[0];
$user{$account_num}{'item1'} += $items[1];
$user{$account_num}{'item2'} += $items[2];
$user{$account_num}{'item3'} += $items[3];
$user{$account_num}{'item4'} += $items[4];
$user{$account_num}{'item5'} += $items[5];
$user{$account_num}{'item6'} += $items[6];

允许您使用

for my $i (0..$#items) {
    $user{$account_num}{"item$i"} += $items[$i];
}

答案 1 :(得分:4)

你在想它。

我可以说,因为我一直这样做:

  

:如果我制造的设备能够以合适的频率振动插座,我可以将灯泡拧紧并拧开。然后我可以将设备连接到插座......

     

我儿子:爸爸,你为什么不用电灯开关?

如果你有一大堆名为item1item2item3等的项目,为什么不把它作为一个项目数组呢?然后你会有$item[0]$item[1]等。这会大大简化你的代码:

for item ( @items ) {
    $user{$account_name}->[$item] += $items[item];
}

也许您使用item1item2作为实际变量名称的替身。也许他们是$widget$left_handed_smoke_shifter。在这种情况下,您可以将其设为项目的哈希值,这样您就可以$item{left_handed_smoke_shifter}$item{widget}。然后,你的循环看起来像这样:

for my $item ( keys %items ) {
    $user{$account_name}->{$item} += $items{$item};
}

简单易懂,易于理解。

但是,如果你真的,真的坚持你需要能够按照你坚持的方式使用变量名,请使用eval

$user{$account_name}->{$varible_name} = eval '$' . "$variable_name";

我只是出售长度足以让人自己悬挂的绳索。他们实际上用它做的不是我的事。

答案 2 :(得分:1)

上面代码的问题是你想使用变量的名称作为键,它可能如下所示:

for my $item ( @items ) {
   $user{$account_num}{$item} = $item
}

问题是$item的值将被用作密钥,而不是其名称。

可能的解决方案:

如果你还有一个关键名列表,这将大大简化:

my @keys = qw(item0 item1 item2 item3 item4 item5 item6);

现在假设您实际上已将所有这些项目都放入子程序中,您可以轻松循环

# 1
sub update_items {
   my @items = @_;

   for my $k ( @keys ) { 
      my $item = shift @items;          # take an item from the front
      $user{$account_num}{$k} += $item; # update
   }
}

或者您可以使用名为hash-slicing的技术,该技术在列表上下文中获取哈希值,并将值列表分配给键列表:

# 2
sub update_items {
   my @items = @_;

   # update all keys of @keys with all values of @items
   @user{$account_num}{@keys} += @items;
}

答案 3 :(得分:1)

以下是Perl调试器中的一个简单示例:

main::(-e:1):   0
  DB<1> @a=('v1', 'v2', 'v3', 'v4')

  DB<2> x @a
0  'v1'
1  'v2'
2  'v3'
3  'v4'
  DB<3> $v1=10
  DB<4> $v2=20
  DB<5> $v3=30
  DB<6> $v4=40

  DB<7> for (@a) { $hash{$_} += $$_ }

  DB<8> x %hash
0  'v4'
1  40
2  'v1'
3  10
4  'v2'
5  20
6  'v3'
7  30
  DB<10>

密钥是$$_,它使用变量间接来获取名称包含在变量中的变量的值,在本例中为$_

答案 4 :(得分:1)

#!/usr/bin/env perl

use strict;
use warnings;

use Data::Dumper;
$Data::Dumper::Indent = 0;

my %user = (
    '0022334401' => [ map int(1000 * rand), 1 .. 7 ],
    '1177459393' => [ map int(1000 * rand), 1 .. 7 ],
);

my $account_id = '0022334401';

print "Before:\n", Dumper($user{$account_id}) ,"\n";

my @vals = (11, 22, 33, 44, 55, 66, 77);

# done setting up. now, update each value for $user{$account_id}
# by adding the value at the corresponding index in @vals

$user{$account_id}[$_] += $vals[$_] for 0 .. $#vals;

print "After:\n", Dumper($user{$account_id}), "\n";

示例输出:

Before:
$VAR1 = [645,553,864,165,463,455,906];
After:
$VAR1 = [656,575,897,209,518,521,983];

答案 5 :(得分:0)

最简洁的方法是使用eval。喜欢这个

$user{$account_num}{$_} += eval "\$$_" for 'item0' .. 'item6'

记得其他人说过的话,你不应该做这类事情。在适当的时候尽快重构代码。