3

我从未使用过 Perl,但我需要完成这个练习。我的任务是以几种不同的方式对数组进行排序。我得到了一个测试脚本。该脚本将数组放在一起,并为其排序的每个阶段打印语句。我将其命名为 foo.pl:

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”包继承了它。最后两种是给我带来问题的。当我创建的 sub: "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;
4

2 回答 2

5

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

你真的很亲近;正确的语法是:

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

另请注意,由于基本上是历史原因,sort将参数传递给(稍微)神奇的全局变量中的比较函数,$a$b不是 in @_,因此您不需要(并且确实不应该)my ($a, $b) = @_;在 sortsubs 中执行(除非您使用原型声明它们;有关详细信息,请参见perldoc -f sort )。


编辑:如果你得到一个比较函数,由于某种原因确实期望它的参数 in @_,并且你不能更改该函数的定义,那么你最好的选择可能是将它包装在这样的闭包中:

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],这可能是一个数组引用。您应该立即取消引用它,如下所示:

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

或者只是暂时保留它作为参考,并在您使用它时取消引用它:

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

编辑3: 一旦您设法对键进行排序,那么,正如duskwuff 在他的原始答案中指出的那样,您还需要Reorder()从您的父类Tie::IxHash调用该方法来实际更改键的顺序。另外,第一行:

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

在应该是一个需要代码引用的对象方法中完全不合适(事实上,如果您想稍后在同一代码块中调用,那么词法化$a并且无论如何都是一个坏主意)。它应该读到的内容类似于:$bsort

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() );
}

(Ps。我现在明白为什么比较函数被指定为接受它们的参数@_而不是全局变量$a以及通常将它们放在$b哪里sort:这是因为比较函数属于不同的包,并且不够$a神奇以至于在每个包都喜欢,说,并且是。我想这可以解决,但它需要一些非常重要的技巧。)$b$_@_caller

(Pps。请在你提交练习时感谢我和黄昏/堆栈溢出。祝你学习 Perl 好运——相信我,拥有这将是一项有用的技能。)

于 2013-01-20T07:06:26.923 回答
4

您的SortKeyByFunc方法返回对数组 ( @sorted) 进行排序的结果,但它不会“就地”修改数组。因此,仅仅调用$t->SortKeyByFunc(...);不会产生任何可见的永久效果。

您需要$t->Reorder()在您的SortKeyByFunc方法中调用才能对阵列产生任何持久影响。我没有尝试过,但类似:

$t->Reorder(@sorted);

在您的方法结束时可能就足够了。

于 2013-01-20T06:05:28.690 回答