2013-01-20 40 views
3

我从来没有使用过Perl,但我需要完成这个练习。我的任务是以几种不同的方式对数组进行排序。我已经提供了一个测试脚本。该脚本将数组放在一起,并为其排序的每个阶段打印语句。我把它命名为foo.pl:为什么我的排序工作不在Perl中?

use strict; 
use warnings; 
use MyIxHash; 

my %myhash; 
my $t = tie(%myhash, "MyIxHash", 'a' => 1, 'abe' => 2, 'cat'=>'3'); 
$myhash{b} = 4; 
$myhash{da} = 5; 
$myhash{bob} = 6; 

print join(", ", map { "$_ => $myhash{$_}" } keys %myhash) . " are the starting key => val pairs\n"; 

$t->SortByKey; # sort alphabetically 
print join(", ", map { "$_ => $myhash{$_}" } keys %myhash) . " are the alphabetized key => val pairs\n"; 

$t->SortKeyByFunc(sub {my ($a, $b) = @_; return ($b cmp $a)}); # sort alphabetically in reverse order 
print join(", ", map { "$_ => $myhash{$_}" } keys %myhash) . " are the reverse alphabetized key => val pairs\n"; 

$t->SortKeyByFunc(\&abcByLength); # use abcByLength to sort 
print join(", ", map { "$_ => $myhash{$_}" } keys %myhash) . " are the abcByLength sorted key => val pairs\n"; 

print "Done\n\n"; 


sub abcByLength { 
    my ($a, $b) = @_; 

    if(length($a) == length($b)) { return $a cmp $b; } 
    else { return length($a) <=> length($b) } 
} 

Foo.pl使用一种称为MyIxHash包,我已经创建了一个名为MyIxHash.pm的模块。该脚本通过按字母顺序排序:“SortByKey”,我通过模块中的“IxHash”包继承。最后两种是给我的问题。当我创建的子集:“SortKeyByFunc”在数组上运行时,它将传递数组和子例程作为参数。我试图接受这些观点并将它们与变量相关联。

最终的排序应该按字符串长度进行排序,然后按字母顺序排序。这个子程序在foo.pl的底部被提供为“abcByLength”。和逆向alpha排序一样,这个子例程作为参数传递给我的SortKeyByFunc子例程。

对于这两种类型,似乎实际的排序工作是为我完成的,我只需要将此子例程应用到我的数组。

我在这里的主要问题似乎是,我不知道如何可能,采取我的子程序参数,并通过它作为参数运行我的数组。我在我的数组上错误地运行了我的方法?

package MyIxHash; 
#use strict; 
use warnings; 
use parent Tie::IxHash; 
use Data::Dumper qw(Dumper); 

sub SortKeyByFunc { 
    #my $class = shift; 
    my ($a, $b) = @_; 

    #this is a reference to the already alphabetaized array being passed in 
    my @letters = $_[0][1]; 

    #this is a reference to the sub being passed in as a parameter 
    my $reverse = $_[1]; 

    #this is my variable to contain my reverse sorted array 
    my @sorted = @letters->$reverse(); 

    return @sorted; 
} 

1; 

回答

5

“出现我的问题,我尝试:my @sorted = @letters->$reverse();我也试过:my @sorted = sort {$reverse} @letters;

你是非常接近;正确的语法是:

my $reverse = sub { $b cmp $a }; 
# ... 
my @sorted = sort $reverse @letters; 

还要注意的是,什么是基本的历史原因,sort传递的参数在(略)魔法全局$a$b比较功能,而不是在@_,所以你不”您需要(并且确实不应该)在您的sortsub中执行my ($a, $b) = @_;(除非您使用原型声明它;详细信息请参阅perldoc -f sort)。


编辑:如果你给一个比较函数,由于某种原因预计@_它的参数,并且不能更改函数的定义,那么你最好的选择可能是将其包装在一个闭包是这样的:

my $fixed_sortsub = sub { $weird_sortsub->($a, $b) }; 

my @sorted = sort $fixed_sortsub @letters; 

或者干脆:

my @sorted = sort { $weird_sortsub->($a, $b) } @letters; 

编辑2:啊,我看到/一个问题。当你写:

my @letters = $_[0][1]; 

你结束了一个什么是含有任何$_[0][1]是,这大概是一个array reference一个单元素数组。您应该取消对它的引用立即,像这样:

my @letters = @{ $_[0][1] }; 

或只保留作为参照现在和解引用它,当你使用它:

my $letters = $_[0][1]; 
# ... 
my @sorted = sort $whatever @$letters; 

编辑3:一旦你可以设法对键进行排序,然后,如他在原始答案中的黄昏笔记所示,还需要调用父类的方法Tie::IxHash以实际更改键的顺序。此外,第一行:

my ($a, $b) = @_; 

完全是出于什么应该是一个对象的方法,需要一个代码引用(而且,事实上,lexicalizing $a$b是一个坏主意无论如何,如果你想要的地方稍后在相同的代码块中调用sort)。它应该读的是一样的东西:

my ($self, $sortfunc) = @_; 

事实上,而不是枚举所有,似乎是错了你的原代码的东西,它可能更容易只是解决它:

package MyIxHash; 
use strict; 
use warnings; 
use parent 'Tie::IxHash'; 

sub SortKeyByFunc { 
    my ($self, $sortfunc) = @_; 

    my @unsorted = $self->Keys(); 

    my @sorted = sort { $sortfunc->($a, $b) } @unsorted; 

    $self->Reorder(@sorted); 
} 

1; 

或者干脆:

sub SortKeyByFunc { 
    my ($self, $sortfunc) = @_; 

    $self->Reorder(sort { $sortfunc->($a, $b) } $self->Keys()); 
} 

(诗我现在明白为什么比较函数被指定为采取他们的论点@_而不是全局$a一个。第二$b其中sort通常把他们:这是因为比较函数属于不同的包,$a$b足够神奇的是一样的在每一个包装公司,比如,$_@_是。我想这可以围绕工作,但它会采取一些非常不平凡的权谋与caller。)

(PPS。请不要信贷我和duskwuff /堆栈溢出,当你在你的锻炼。祝你好运手学习Perl —相信我,这将是一个有用的技能。)

+0

@ user1361666:没问题。如果您找到了解决问题的答案(本或其他),请不要忘记单击左侧的复选标记图标接受答案。 –

+0

谢谢你的回应。 您提供的代码不会抛出任何错误,但它也不会排序我的数组。 当您提到$ a和$ b变量时,您是指我的SortKeyByFunc子例程中的my($ a,$ b)= @;' 或者从foo.pl传入的子例程中的行 ?我问,因为foo.pl是为我提供的脚本,不应该被改变。 当他们打电话给我的子这被传递: '$ T-> SortKeyByFunc(子{我的($ A,$ B)= @_;回报($ B $ CMP一)});' 谢谢寻求帮助。 – Esten

+0

那么,你真正应该做的是去写'foo.pl'的人,问他们在想什么。但是如果你真的必须使用一个外部提供的比较函数,它不符合'sort'使用的通常调用约定,那么你最好的办法就是为它编写一个包装器;看到我上面的编辑。 –

4

SortKeyByFunc方法返回排序阵列(@sorted)的结果,但它并不“就地”修改数组。因此,拨打$t->SortKeyByFunc(...);并不会产生任何明显的永久效应。

您需要在SortKeyByFunc方法内调用$t->Reorder()以对阵列产生持续影响。我还没有尝试过,但是像这样:

$t->Reorder(@sorted); 

在您的方法结束可能已经足够。

+0

'@ sorted'中的数组还没有正确的排序数组。出现我的问题,我尝试: '我@sorted = @letters - > $反向();' 我也试过: '我@sorted =排序{$扭转} @letters;' – Esten