LINUX.ORG.RU

Perl и ссылки


0

0

Добрый день.

Пусть есть массив @a из 50 элементов, от 1 до 50. Я хочу разбить его
на 5 частей и занести в другой массив @res, что первый элемент содержал
массив 1..10, второй 11..20 и тд. Итак:

@a = (1..50);
@res = ();

for ($i = 0; $i < 5; $i++) {
    $begin  = 10 * $i;
    $end    = 10 * ($i + 1) - 1;
    @a_slice = @a[$begin..$end];  # копируем срез во временный массив
    push @res, \@a_slice;         # и в новом массиве делаем на него ссылку
}

печатаем аолучившийся массив на экран:
for ($i = 0; $i < 5; $i++) {
    for ($j = 0; $j < 10; $j++) {
        printf " %2d", ${$res[$i]}[$j];
    }
    print "\n";
}

 41 42 43 44 45 46 47 48 49 50
 41 42 43 44 45 46 47 48 49 50
 41 42 43 44 45 46 47 48 49 50
 41 42 43 44 45 46 47 48 49 50
 41 42 43 44 45 46 47 48 49 50

ну понятно. В окончательном массиве мы имеем пять ссылок на один и тот
же массив, который 5 раз обновлялся, и в последний раз туда записались
последние 10 из 50 элементов.
Ладно. Открываю perlref(tut) и читаю, что ссылки в Perl - это как
жесткие ссылки в Unix. Ага. Это в Unix означает, что у файла просто
2 имени - меняем содержимое одного, меняется, естественно, и у
другого - оба имени ссылаются на одну область памяти. Но если мы
удаляем одно из имен, то содержимое файла сохраняется - до тех пор,
пока мы не удали все имена. Поэтому я решил после того, как занес
в новый массив ссылку на @a_slice, сделать
  undef @a_slice;

Но в итоге и ссылки в @res стали указывать на пустое место :(
То есть ссылки в Perl действуют несколько по-другому...

Как мне быть с моей задачей? Каждый раз в цикле называть временные
переменные по-разному?

Спасибо всем, кто поможет!

#!/usr/bin/env perl
@a = (1..50);
@res = ();

for ($i = 0; $i < 5; $i++) {
    $begin  = 10 * $i;
    $end    = 10 * ($i + 1) - 1;
#    @{$res[$i]} = @a[$begin..$end];
    printf " %2d" => $_ for @a[$begin..$end];
    print "\n";
}
=pod
for ($i = 0; $i < 5; $i++) {
    for ($j = 0; $j < 10; $j++) {
        printf " %2d" => $res[$i][$j]
    }
    print "\n";
}
=cut

Но я бы использовал массив массивов, имхо это проще. 
Или тебе надо обязательно через ссылки?

vilfred ☆☆
()

по поводу ссылок, может я конечно ошибаюсь, но вроде есть соответствие ссылка на область памяти - название переменной, т.е. ты передаешь ссылку на область памяти с названием a_slice и на последней итерации цикла она заполняется элементами 41 .. 50

И далее во втором цикле ты последовательно извлекаешь данные по ссылке не с пяти областей памяти, а с одной, которая была заполнена на последней итерации цикла.

vilfred ☆☆
()
Ответ на: комментарий от vilfred

Минимальным изменение в приведенном коде которое заставит его работать правильно будет замена
@a_slice = @a[$begin..$end];
на 
my @a_slice = @a[$begin..$end];
Т.е. новая переменная с новым адресом будет создаваться на каждом витке цикла.
Но вообще-то можно все это записать гораздо короче.
Например вот так:

my @a = (1..50);
my $cnt=10;
my @res;

push @res, [splice(@a, 0, $cnt)] while @a;
map {print join(' ', @{$_}),"\n"} @res;

cvasil
()
Ответ на: комментарий от cvasil

может быть и так, я со ссылками до конца еще не разобрался...

vilfred ☆☆
()
Ответ на: комментарий от vilfred

>> Но я бы использовал массив массивов, имхо это проще.
>> Или тебе надо обязательно через ссылки?
Без ссылок, насколько мне известно (я еще совсем новичок), не
получится. Почитай perlreftut.

murla
() автор топика
Ответ на: комментарий от cvasil

>> push @res, [splice(@a, 0, $cnt)] while @a;
>> map {print join(' ', @{$_}),"\n"} @res;
Спасибо, изящно! :) Я не знал про splice :) Мне в другом форму
сказали, что можно использовать прямо [@a[$begin..$end]], у меня была
такая идея, но я почему-то сразу решил, что это не будет работать :-/

murla
() автор топика
Ответ на: комментарий от murla

так ведь получилось же :) надо только комментсы убрать. А ваще, там все можно несколькими способами сделать...

vilfred ☆☆
()
Ответ на: комментарий от vilfred

>> так ведь получилось же :) надо только комментсы убрать. А ваще,
>> там все можно несколькими способами сделать...
Да, действительно :) Я увидел, что ты не знаешь про ссылки, и дальше
твой вариант не стал разбирать. Но там действительно все верно.
  @{$res[$i]} = @a[$begin..$end];
Здесь `$res[$i]' - ссылка на _анонимный_ массив, который заполняется
элементами из массива @a. А вот это:
  $res[$i][$j]
- сокращение от $res[$i]->[$j], $j-й элемент анонимного массива, на
который ссылается $res[$i].

Все равно спасибо :)

murla
() автор топика
Ответ на: комментарий от murla

perl -e '$rr[10][10][10][10]="qq"; print "$rr[10]->[10]->[10]->[10]\n"'

Надеюсь, понятно, почему так можно писать, но лучше не нужно...

Мужик, я тебе всяких разных стрелок могу понаставить во всей программе, я конешно понимаю, вые#нуться хочеться, сам такой был... но пора бы уже взрослеть и не вые&#8470;ываться, а ченнить писать самому полезное и уникальное, чтобы нигде не было, и это новое и полезное в новости давать для всеобщего пользования.

p.s. а ссылки все равно надо конешно подюзать, я просто ввообще обходился без ссылок как то, столько тут возможностей сделать одно и тоже разными способами...

vilfred ☆☆
()
Ответ на: комментарий от vilfred

Что я хотел у теябя спросить? Пожалуйста:

1) Как ты обходился без жестких ссылок

2) Писал ли ты на perl4

3) Чего ты такой злобный

anonymous
()
Ответ на: комментарий от anonymous

1) не нужно было просто...

2) нет, я начал изучать перл, когда уже был 5-й

3) некий опыт есть, чтобы распознать когда злобны по отношению ко мне, потому чего это я буду добреньким...

vilfred ☆☆
()
Ответ на: комментарий от anonymous

вообще если я правильно понял архитектуру прог, где употреблюятся жесткие ссылки, то я юзал для замены сначала модуль IPC::Shaerable, а дальше забил и теперь посылаю исключения. Если толко я правильно понял, что жесткие ссылки нужны для того, чтобы обращаясь к разным переменных получать одинаковые значения. Короче, не шарящий чел.

vilfred ☆☆
()
Ответ на: комментарий от murla

"Здесь `$res[$i]' - ссылка на _анонимный_ массив, который 
заполняется элементами из массива @a." - стой, погоди, я чето 
не вдумался, это вроде как массив массивов и он не анонимный 
потому, что поименован индексом. Или я че не понял в этой жизни? 
Конструкция @{} нужна, чтобы к переменной $rr[$i] обращаться как к 
массиву, ведь массив массивов может быть на 10-м элементе и 
массивом с одним элементом... Она именно поименована... 

#!/usr/bin/env perl
@a = (1..50);
@res = ();

for ($i = 0; $i < 5; $i++) {
    $begin  = 10 * $i;
    $end    = 10 * ($i + 1) - 1;
    @{$res[$i]} = @a[$begin..$end] if $i!=2;
    $res[$i] = "xxx" if $i==2;
    print "\n";
}
for ($i = 0; $i < 5; $i++) {
    for ($j = 0; $j < 10; $j++) {
        printf " %2d" => $res[$i][$j] if ref ($res[$i]) eq "ARRAY";
        print $res[$i] if ref ($res[$i]) ne "ARRAY";
    }
    print "\n";
}

vilfred ☆☆
()
Ответ на: комментарий от vilfred

боюсь, что тут не все так просто как кажется и надо какннить реально подучить ссылки... сильная это штука, ссылки то.

vilfred ☆☆
()
Ответ на: комментарий от vilfred

To vilfred. Скажу сразу для ясности, что каким-то образом обижать
или смеяться над тобой и в мыслях не было. Более того, высмеивание
тех, кто просто не знает каких-то возможности языка, считаю
идиотизмом. Молчу уж о том, что в Перле я пока ну очень слаб.
Ладно, далее.

>>  @{$res[$i]} = @a[$begin..$end] if $i!=2;
>>  "Здесь `$res[$i]' - ссылка на _анонимный_ массив, который 
>>  заполняется элементами из массива @a." - стой, погоди, я чето 
>>  не вдумался, это вроде как массив массивов и он не анонимный 
>>  потому, что поименован индексом. Или я че не понял в этой жизни? 
>>  Конструкция @{} нужна, чтобы к переменной $rr[$i] обращаться как к 
$res[$i] - это _скаляр_, о чем уже говорит знак доллара вначале.
В Perl'овых массивах, как и хешах, элементами могут быть _только_
скаляры. Еще раз ссылаюсь на perdoc perlreftut - там предельно
просто и доступно все написано. Ты на С никогда не писал? Прямая
аналогия, это просто указатель на массив. Конструкция @{$чтонибудь}
велит интерпретировать величину $чтонибудь как указатель. То есть
в $что-нибудь находится адрес ячейки памяти, где этот массив
валяется (первый его элемент). Вот и все. И имя этому массиву
присваивать не обязательно, главное - адрес есть.

murla
() автор топика
Ответ на: комментарий от murla

"То есть в $что-нибудь находится адрес ячейки памяти, где этот массив валяется (первый его элемент)." - постой, но все равно ведь числовое извлечение происходит, по номеру элемента массива (ты для того чтобы извлечь данные по 10 му элементу не к абстрактной ссылке обращаешься, а пишешь 10). Да, с некоторой точки зрения там все есть ссылка (хотябы потому что не ref оно само ответило), я даже думаю, что строчка $a=5 механически тоже ссылка...

Я на сях вообще не писал, потому у меня немного иной взгляд на некоторые вещи... ты вон даже вместо принт пишешь принтф, я не сишник вообще, поэтому некоторые мои слова звучат немного не так, ну штож, такива жиссььь :)

меня тут удивило недавно, что это дает четыре без всяких %d или что там надо писать: perl -e '$xx="2*2"; printf eval $xx'

vilfred ☆☆
()
Ответ на: комментарий от vilfred

>>  Да, с некоторой точки зрения там все есть ссылка (хотябы потому
>>  что не ref оно само ответило), я даже думаю, что строчка $a=5
>>  механически тоже ссылка...
Именно! :-)

>>  ты вон даже вместо принт пишешь принтф
Ну когда нужон красивый вывод, то да. А вообще как раз НЕ хочу чтоб
выглядело похожим на С. Иначе зачем я тогда с него слезал :-)

murla
() автор топика
Ответ на: комментарий от murla

по поводу красивого вывода такой код у меня есть:

my $string = swrite(<<'END', '30.0', $ra, $sign,$dec111,$pos);
@<<<<<<<<<@<<<<<<<<<@@<
<<<<<<<<@<<<<<<<<<
END

sub swrite {
  croak "usage: swrite PICTURE ARGS" unless @_;
  my $format = shift;
  $^A = "";
  formline($format,@_);
  return $^A;
}

vilfred ☆☆
()
Ответ на: комментарий от vilfred

Ты попробуй этот свой код для красивого вывода использовать в проекте, где кроме тебя ещё другие разработчики есть.

Тебе быстро объяснят, почему так писать нельзя.

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.