【问题标题】:Converting code to perl sub, but not sure I'm doing it right将代码转换为 perl sub,但不确定我做得对
【发布时间】:2010-06-14 02:07:40
【问题描述】:

我正在处理我之前发布的问题 (here),并尝试将答案转换为 sub,以便我可以多次使用它。不确定它是否正确完成。谁能提供更好或更清洁的潜艇?

我有很多编程经验,但我的主要语言是 PHP。知道如何用一种语言执行,却不能用另一种语言执行,这令人沮丧。

sub search_for_key
{
    my ($args) = @_;

    foreach $row(@{$args->{search_ary}}){
        print "@$row[0] : @$row[1]\n";
    }

    my $thiskey = NULL;

    my @result = map { $args->{search_ary}[$_][0] }     # Get the 0th column...
        grep { @$args->{search_in} =~ /$args->{search_ary}[$_][1]/ } # ... of rows where the
            0 .. $#array;                               #     first row matches
        $thiskey = @result;

    print "\nReturning: " . $thiskey . "\n";
    return $thiskey;    
}

search_for_key({
    'search_ary' => $ref_cam_make, 
    'search_in' => 'Canon EOS Rebel XSi'
});

---编辑---

从目前的答案来看,我拼凑了下面的函数。我是 Perl 的新人,所以我不太了解其中的语法。我所知道的是它会引发关于该 grep 行的错误(不是第 26 行的 ARRAY 引用。)。

由于我似乎没有提供足够的信息,所以我还要提一下:

我这样调用这个函数(可能正确也可能不正确):

search_for_key({
    'search_ary' => $ref_cam_make, 
    'search_in' => 'Canon EOS Rebel XSi'
});

$ref_cam_make 是我从数据库表中收集的一个数组,如下所示:

$ref_cam_make = $sth->fetchall_arrayref;

它的结构是这样的(如果我了解如何使关联提取正常工作,我想像那样使用它而不是数字键):

Reference Array
Associative
row[1][cam_make_id]: 13, row[1][name]: Sony

Numeric
row[1][0]: 13, row[1][1]: Sony
row[0][0]: 19, row[0][1]: Canon
row[2][0]: 25, row[2][1]: HP

sub search_for_key
{
    my ($args) = @_;

    foreach my $row(@{$args->{search_ary}}){
        print "@$row[0] : @$row[1]\n";
    }

    print grep { $args->{search_in} =~ @$args->{search_ary}[$_][1] } @$args->{search_ary};
}

【问题讨论】:

  • 您在脚本/模块的顶部缺少use strict; use warnings;。它将捕获许多错误并使您看到的诊断更有帮助(当您的示例代码中已经修复了这些简单错误时,SO 上的人更有可能为您提供帮助)。
  • @Ether ...此代码是从较大脚本中复制粘贴的。我在完整脚本中使用了严格和警告。
  • foreach $row(@{$args->{search_ary}}){ 说你没有。或者,你忽略了你得到的错误,这同样糟糕。
  • @Ether 请阅读整篇文章并查看编辑行下方的信息和新功能。

标签: perl function


【解决方案1】:

您正朝着二维数组的方向移动,其中[0] 元素是某种 ID 号,[1] 元素是相机制造商。尽管以一种快速而肮脏的方式是合理的,但这种方法很快就会导致代码不可读。如果您使用更丰富、更具声明性的数据结构,您的项目将更易于维护和发展。

下面的示例使用哈希引用来表示相机品牌。一个更好的方法是使用对象。当您准备好迈出这一步时,请查看Moose

use strict;
use warnings;

demo_search_feature();

sub demo_search_feature {
    my @camera_brands = (
        { make => 'Canon', id => 19 },
        { make => 'Sony',  id => 13 },
        { make => 'HP',    id => 25 },
    );

    my @test_searches = (
        "Sony's Cyber-shot DSC-S600",
        "Canon cameras",
        "Sony HPX-32",
    );

    for my $ts (@test_searches){
        print $ts, "\n";
        my @hits = find_hits($ts, \@camera_brands);
        print '  => ', cb_stringify($_), "\n" for @hits;
    }
}

sub cb_stringify {
    my $cb = shift;
    return sprintf 'id=%d make=%s', $cb->{id}, $cb->{make};
}

sub find_hits {
    my ($search, $camera_brands) = @_;
    return grep { $search =~ $_->{make} } @$camera_brands;
}

【讨论】:

    【解决方案2】:

    这整个 sub 真的很混乱,而且我是一个相当普通的 perl 用户。以下是一些笼统的建议。

    • 永远不要创建自己的undef - 使用undef,然后在底部返回return $var // 'NULL'
    • 永远不要这样做:foreach $row,因为foreach my $row 不太容易产生问题。本地化变量很好。
    • 不要不必要地连接,因为它冒犯了风格之神:不是这个,print "\nReturning: " . $thiskey . "\n";,而是print "\nReturning: $thiskey\n";,或者如果你不需要第一个\nsay "Returning: $thiskey;"(仅限5.10)
    • greping over 0 .. $#array; 绝对是蹩脚的,只是对数组进行 grep:grep {} @{$foo[0]},并且由于该代码如此复杂,您几乎肯定不想要 grep(尽管我不明白您在做什么)老实说。)。查看perldoc -q first——简而言之grep 不会停止到最后

    最后,不要将数组分配给标量:$thiskey = @result; 是一个隐含的$thiskey = scalar @result;(请参阅perldoc -q scalar)以获取更多信息。您可能想要的是返回数组引用。像这样的东西(消除了$thiskey

    printf "\nReturning: %s\n", join ', ', @result;
    @result ? \@result : 'NULL';
    

    【讨论】:

    • 很好的建议,++。但是,请注意可能具有误导性的词汇:“本地化变量很好”。在“编程”的背景下,这是一个很好的建议。在“Perl 编程”的上下文中,您的陈述具有误导性,因为它可以被理解为意味着词法和动态范围是等价的。 local 和“localize”在 Perl 中具有特定含义,这与 localize 的正常 comp sci 含义不同,即“限制范围”。将句子更改为“最小化变量范围是好的”怎么样。或类似的东西?
    • 我宁愿使用correct term,也不愿使用特定于perl的解决方法,以避免与很少使用的变量声明local相混淆。
    【解决方案3】:

    如果您打算返回是否找到匹配项,则此代码应该可以工作(效率低下)。但是,如果您打算返回密钥,则不会 - @result 的标量值(当您说 $thiskey = @result; 时得到的)是列表中的项目数,而不是第一个条目。

    $thiskey = @result; 可能应该更改为$thiskey = $result[0];,如果您想要与您基于此的代码基本等效的功能。请注意,它不会再考虑多个匹配项,除非您完整地返回 @result,否则这更有意义。

    【讨论】:

      猜你喜欢
      • 2017-05-06
      • 2011-03-14
      • 1970-01-01
      • 1970-01-01
      • 2020-01-18
      • 1970-01-01
      • 2022-01-26
      • 2020-08-11
      • 2022-11-12
      相关资源
      最近更新 更多