将代码转换为perl sub,但不确定我做得对

时间:2010-06-13 14:55:52

标签: perl function

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

我有很多编程经验,但我的主要语言是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'
});

--- ---编辑

从目前为止的答案中,我拼凑了下面的功能。我是 new 到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};
}

3 个答案:

答案 0 :(得分:5)

您正朝着2D数组的方向移动,其中[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;
}

答案 1 :(得分:4)

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

  • 请勿创建自己的undef - 使用undef然后在底部return $var // 'NULL'返回。
  • 不要这样做:foreach $row,因为foreach my $row不太容易造成问题。本地化变量很好。
  • 不要不必要地连接,因为它冒犯了风格的神:不是这个,print "\nReturning: " . $thiskey . "\n";,而是print "\nReturning: $thiskey\n";,或者如果你不需要第一个\n:{{1} }(仅限5.10)
  • say "Returning: $thiskey;" grep0 .. $#array;完全蹩脚,只是grep over the array: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';

答案 2 :(得分:1)

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

$thiskey = @result;应该更改为$thiskey = $result[0];,如果您希望与基于此功能的代码具有大致相同的功能。请注意,它不再考虑多个匹配,除非您完整地返回@result,无论如何哪种更有意义。