Как добавить строку в матрицу (массив ссылок)? - PullRequest
1 голос
/ 06 марта 2012

У меня есть модуль со следующими подпрограммами:

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 ]

4 голосов
/ 06 марта 2012

Да, вы добавляете массив ref, но ваша переменная является массивом

Первое, что вам нужно сделать (после использования строгих правил и предупреждений), это прочитать следующую документацию по сигилам в Perl (кроме хорошей книги по Perl):

Лучшее резюме, которое я могу дать вам о синтаксисе доступа к структурам данных в Perl, - это (цитата из моего предыдущего комментария)

  • символ представляет количество данных из структуры данных, которую вы извлекаете ($ 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' )
    ];
2 голосов
/ 06 марта 2012

Хорошо, сделайте резервную копию.

Сначала вам нужно набрать 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.

1 голос
/ 06 марта 2012

Просто пара вещей:

  • Используйте Local::Module вместо module. Пространство модуля Local зарезервировано для модулей не-CPAN. Также, по соглашению, имена модулей должны начинаться с заглавной буквы.
  • Используйте use strict и use 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, мне не нужно изменять конструктор. Изменения изолированы в одном месте.

0 голосов
/ 06 марта 2012

@ _ - это временная переменная, используемая только для передачи аргументов функции, поэтому помещение аргументов в нее не приводит к изменению самого объекта.

Вместо этого вам необходимо извлечь объект из @_ массив и затем измените его.

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