1

我有一个数组散列和一个普通数组,根据情况(即用户在程序运行时选择的选项),只会定义其中一个。

演示问题的示例代码:

my %hashofarrays;
my @array;

#...
#Some code between here where either %hashofarrays or @array gets defined
#...

if (defined @array) {

    foreach my $var1 (@array) {
        print "var1 is: $var1\n";
        call_subroutine($var1);
        print "Something else is printed";
        call_anothersubroutine($var1);
        call_differentsubroutine($var1);
    }

} 

if (defined %hashofarrays) {

    foreach my $key (keys %hashofarrays) {
        print "the key is: $key\n";
        foreach my $var1 (@{$hashofarrays{$key}}) {
            call_subroutine($var1);
            print "Something else is printed";
            call_anothersubroutine($var1);
            call_differentsubroutine($var1);
        }
    }
}
   

正如您在上面的代码中看到的,取决于是否@array定义了或是否%hashofarrays定义了它,它将运行相应的if语句。

问题:

但是,问题在于以下代码行在两个if语句中都重复:

    call_subroutine($var1);
    print "Something else is printed";
    call_anothersubroutine($var1);
    call_differentsubroutine($var1);

显然,如果这些foreach循环包含大量代码,那将意味着大量代码将被复制。

foreach当涉及到循环时,有什么方法/什么是可以避免这种代码重复的最佳方法?

实际上,有没有办法执行以下操作:(我很清楚这段代码不起作用,但解释了我想要实现的目标)

if (defined @array) {
    foreach my $var1 (@array) {
} elsif (defined %hashofarrays) {
    foreach my $key (keys %hashofarrays) {
        print "the key is: $key\n";
        foreach my $var1 (@{$hashofarrays{$key}}) {

} #ending bracket of if statement

        call_subroutine($var1);
        print "Something else is printed";
        call_anothersubroutine($var1);
        call_differentsubroutine($var1); 

}  #ending bracket of whatever foreach loop is used

我很可能在这里忽略了一些明显的东西,但看不到这样做的合乎逻辑的方法?

4

3 回答 3

5

首先,defined @array而且defined %hashofarrays错误的。它们总是被定义的。您想要if (@array)if (keys %hashofarrays)测试它们是否包含元素。你甚至应该得到警告defined(@array) is deprecated

你想要的是另一个子程序。

sub loop_body {  # just use some better name!
  my ($var) = @_;
  call_subroutine($var);
  print "Something else is printed";
  call_anothersubroutine($var);
  call_differentsubroutine($var);
}

然后:

if (@array) {
    foreach my $var1 (@array) {
        print "var1 is: $var1\n";
        loop_body($var1);
    }
} elsif (keys %hashofarrays) {
    foreach my $key (keys %hashofarrays) {
        print "the key is: $key\n";
        foreach my $var1 (@{$hashofarrays{$key}}) {
            loop_body($var1)
        }
    }
}

您还可以使用回调使您的解决方案更加灵活:

 sub loop_with_cb {
   my $cb = shift;
   for my $var (@_) {
     if ($cb) {
       local $_ = $var; # make $_ visible to the callback
       $cb->($var);
     }
     call_subroutine($var);
     print "Something else is printed";
     call_anothersubroutine($var);
     call_differentsubroutine($var);
   }
 }

然后:

if (@array) {
    loop_with_cb(
      sub { print "var1 is: $_\n" },
      @array,
    );
} elsif (keys %hashofarrays) {
    foreach my $key (keys %hashofarrays) {
        print "the key is: $key\n";
        loop_with_cb(undef, @{ $hashofarrays{$key} });
    }
}
于 2013-09-03T12:10:37.270 回答
1

使用其他功能可能会有所帮助,

if (@array) {
    my_func(\@array);
} 
if (%hashofarrays) {
    foreach my $key (keys %hashofarrays) {
        print "the key is: $key\n";
        my_func($hashofarrays{$key});
    }
}

sub my_func {
    my ($arr) = @_;

    foreach my $var1 (@$arr) {
        call_subroutine($var1);
        print "Something else is printed";
        call_anothersubroutine($var1);
        call_differentsubroutine($var1);
    }

}
于 2013-09-03T12:13:36.617 回答
0

正如 amon 所说,if (defined @array)这是错误的,但我什至不会打扰,if (@array)除非你将拥有一个else. 你可以直接去for (@array),如果@array是空的,它将迭代零次,基本上就像跳过循环一样if

这样一来,您似乎想对 in 中的每个元素和 in 中的@array每个键执行相同的操作%hash of arrays,对吗?你甚至不需要一个sub

for (@array, map { @$_ } values %hashofarrays) {
  my $var1 = $_;
  print "var is: $var1\n";
  call_subroutine($var1);
  print "Something else is printed";
  call_anothersubroutine($var1);
  call_differentsubroutine($var1);
}

编辑:修改代码以循环遍历数组的内容%hashofarrays而不是其键。这仍然与初始问题中的代码不完全匹配,因为它$var1在循环遍历 hoa 时打印而不是打印哈希键,但看起来 OP 的真实用例很有可能不使用除了索引到散列之外的任何东西的键,在这种情况下,无论如何都不需要它(因为我们可以使用它values %hoa)。

于 2013-09-03T12:50:25.933 回答