如何在矩阵(引用数组)中添加一行?

时间:2012-03-06 16:47:43

标签: arrays perl module subroutine

我有一个包含以下子程序的模块:

package module;

sub new
{
    my $class = shift;
    my $reference = shift;
    bless $reference, $class;
    return $reference;
};

sub add_row{

    @newrow = [1,1,1];
    push @_, @newrow;

};

@matricies是数组引用的数组。我使用

从数组引用中创建了对象
my @object= map{module->new($_)} @matrices;

并且假设我想使用以下命令向其中一个对象添加行:

@object[0]->add_row();

我认为add_row子程序处理@和$的使用有问题。有什么想法吗?

4 个答案:

答案 0 :(得分:4)

是的,您正在添加数组引用,但您的变量是一个数组。

你需要做的第一件事(在使用严格和警告之后)是阅读以下关于Perl中的符号的文档(除了好的Perl书):

我可以为您提供有关在Perl中访问数据结构的语法的最佳摘要(引自我之前的评论)

  
      
  • sygil表示您要检索的数据结构中的数据量(1个元素的$,元素列表的@,整个哈希的%)

  •   
  • 而大括号样式代表你的数据结构(数组的正方形,散列的卷曲)。

  •   

现在,为您的代码:

@newrow = [1,1,1];
push @_, @newrow;

应该是

my $newrow = [1,1,1];
push @_, $newrow;

如何从对象访问行还有另一个问题:

sub add_row {
    my ($self, $newrow) = @_;
    $newrow ||= [1,1,1]; # In case it wasn't passed, default to this?
    push @{$self}, $newrow;
};

你对@object[0]->add_row();和newrow也有同样的问题 - 你使用数组sigil来解决1个元素

$object[0]->add_row(); # will add default row of [1,1,1]
$object[0]->add_row([2,3,4]);

更新:这是一个完整的代码:

模块的add_row()(你的构造函数很好):

sub add_row {
    my ($self, $newrow) = @_;
    $newrow ||= [1,1,1]; # In case it wasn't passed, defauly to this?
    push @{$self}, $newrow;
};

测试驱动程序:

use a1;
my @objects = (a1->new([[5,6,7],[8,9,10]]));
$objects[0]->add_row();
$objects[0]->add_row([3,4,5]);
use Data::Dumper; print Data::Dumper->Dump([\@objects]);

结果:

$VAR1 = [
      bless( [
               [
                 5,
                 6,
                 7
               ],
               [
                 8,
                 9,
                 10
               ],
               [
                 1,
                 1,
                 1
               ],
               [
                 3,
                 4,
                 5
               ]
             ], 'a1' )
    ];

答案 1 :(得分:2)

好的,备份。

首先,您需要use strict;use warnings;。总是。每一次都是。如果你不这样做,那你就是在乞求麻烦。

此外,@newrow = [1,1,1];不正确,因为@newrow表示数组,但[1,1,1]是数组引用。此外,@newrow仅在您的子例程中定义,因此add_row实际上没有做任何事情。您需要的是将引用传递给要添加行的矩阵。

我认为你要做的是将矩阵建模为数组引用数组。所以,例如,如果我们有

my @matrix=([1,0,0],[0,1,0],[0,0,1]);

然后可以将其视为包含[1,0,0][0,1,0][0,0,1]行的矩阵。

因此,忽略了创建模块的想法,您可能正在寻找的内容如下:

use strict;   #ALWAYS
use warnings; #ALWAYS

#array of three array references, each of which has three elements.
my @matrix=([1,0,0],[0,1,0],[0,0,1]);

#The arguments to add_row are (in order):
#1.  A reference to the matrix to which you want to add a row.
#2.  A list of the elements that you wish to add.

sub add_row
{
  my $matrix_arg=shift;
  my @new_row_array=@_;

  #Now, we do the necessary push:
  push @$matrix_arg,\@new_row_array;
}

#Now we can add a row and check whether or not we we are successful:

add_row(\@matrix,2,-17,5);

foreach my $row (@matrix)
{
  print join(",",@$row) . "\n";
}

输出结果为:

1,0,0
0,1,0
0,0,1
2,-17,5

老实说,我建议您亲自阅读Learning Perl的副本并查看perldoc perlref

答案 2 :(得分:1)

只是一些事情:

  • 使用Local::Module代替moduleLocal模块空间保留给非CPAN模块。此外,按照惯例,模块名称应以大写字母开头。
  • 使用use strictuse warnings

让我们看一下你的new 子程序构造函数:

sub new
{
    my $class = shift;
    my $reference = shift;
    bless $reference, $class;
    return $reference;
};

我不确定你在这里尝试做什么。通常,这应该是一个构造函数。你得到一个引用对象,你不会传给它一个引用。也许你的意思是这个?

package Local::Module;
sub new {
   my $class = shift;

   my $reference = {};
   bless $reference, $class;
   return $reference;
}

这将创建一个可用于添加的新对象。所以,你先做到这一点:

 my $object = Local::Module->new;

现在,您可以使用$object作为行的句柄:

sub add_rows {
   my $self = shift;
   my $rowRef = shift;

   if (not exists $self->{ROWS}) {
       $self->{ROWS} = [];
   }
   push @{$self->{ROWS}}, $rowRef;
}

现在,您可以使用此对象添加行:

 my $object->add_row = $RowReference;

请注意,Perl中的对象通常是对匿名哈希的引用。您将所需的数据放在哈希的其中一个键中。在这种情况下,您将数组放入$ self-> {ROWS}。

是的,有各种各样的方法可以创建伪哈希,内部哈希,但想法是你的类通常不是实际数据,而是对保存数据的对象的引用。否则,你并没有真正使用面向对象的编程。

在你的情况下,我不会打扰map。我怀疑它会更有效率,并且for循环将更清洁(未经测试):

use strict;
use warnings;

my @matrices = ([1,0,0],[0,1,0],[0,0,1]);

my @objects;
foreach my $array_ref (@matrices) {
   my $module_ref = Local::Module->new;
   my $module_ref->add_row($array_ref);
   push @objects, $module_ref;
}


package Local::Module;
sub new {
   my $class = shift;

   my $reference = {};
   bless $reference, $class;
   return $reference;
}


sub add_rows {
   my $self = shift;
   my $rowRef = shift;

   if (not ref($rowRef) eq "ARRAY") {
       die qq(Method "add_rows" can only take an Array reference);
   }

   if (not exists $self->{ROWS}) {
       $self->{ROWS} = [];
   }
   push @{$self->{ROWS}}, $rowRef;
}

现在,您的@objects列表是Local::Module类的列表。你现在可以这样做:

  $objects[2]->add_row($row_ref);

这是一个非常粗略的轮廓。例如,您可能希望另一个模块返回对所有数组的引用。也许另一个可以弹出并移动数组中的行,并返回弹出或移位的行。

您可能还想要包含一种传递对数组的初始引用的方法:

sub new {
   my $class = shift;
   my $array_ref = shift;

   my $reference = {};
   bless $reference, $class;
   if (defined $array_ref) {
       $reference->add_row($array_ref);
   }
   return $reference;
}

请注意,一旦我祝福$reference,我就可以在面向对象的调用中使用它。这样,我的构造函数不知道我的对象是什么样的。一般认为构造函数和方法应该不知道对象的其余部分是如何构造的。这样,当您修改对象时,您只需要修改一个或两个隔离的方法。如果我改变方法add_rows的工作方式,我不必修改我的构造函数。更改将在一个位置隔离。

答案 3 :(得分:0)

@_是一个临时变量,仅用于将参数传递给函数,因此将参数放在其上不会修改对象本身。

相反,您需要从@_数组中取出对象,然后再修改它。

sub add_row{
    my $self = shift;
    @newrow = (1,1,1);
    push @$self, @newrow;
};