Добрый день.
Пусть есть массив @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 действуют несколько по-другому...
Как мне быть с моей задачей? Каждый раз в цикле называть временные
переменные по-разному?
Спасибо всем, кто поможет!
по поводу ссылок, может я конечно ошибаюсь, но вроде есть соответствие ссылка на область памяти - название переменной, т.е. ты передаешь ссылку на область памяти с названием a_slice и на последней итерации цикла она заполняется элементами 41 .. 50
И далее во втором цикле ты последовательно извлекаешь данные по ссылке не с пяти областей памяти, а с одной, которая была заполнена на последней итерации цикла.
Минимальным изменение в приведенном коде которое заставит его работать правильно будет замена
@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;
>> Но я бы использовал массив массивов, имхо это проще.
>> Или тебе надо обязательно через ссылки?
Без ссылок, насколько мне известно (я еще совсем новичок), не
получится. Почитай perlreftut.
>> push @res, [splice(@a, 0, $cnt)] while @a;
>> map {print join(' ', @{$_}),"\n"} @res;
Спасибо, изящно! :) Я не знал про splice :) Мне в другом форму
сказали, что можно использовать прямо [@a[$begin..$end]], у меня была
такая идея, но я почему-то сразу решил, что это не будет работать :-/
>> так ведь получилось же :) надо только комментсы убрать. А ваще,
>> там все можно несколькими способами сделать...
Да, действительно :) Я увидел, что ты не знаешь про ссылки, и дальше
твой вариант не стал разбирать. Но там действительно все верно.
@{$res[$i]} = @a[$begin..$end];
Здесь `$res[$i]' - ссылка на _анонимный_ массив, который заполняется
элементами из массива @a. А вот это:
$res[$i][$j]
- сокращение от $res[$i]->[$j], $j-й элемент анонимного массива, на
который ссылается $res[$i].
Все равно спасибо :)
Надеюсь, понятно, почему так можно писать, но лучше не нужно...
Мужик, я тебе всяких разных стрелок могу понаставить во всей программе, я конешно понимаю, вые#нуться хочеться, сам такой был... но пора бы уже взрослеть и не вые№ываться, а ченнить писать самому полезное и уникальное, чтобы нигде не было, и это новое и полезное в новости давать для всеобщего пользования.
p.s. а ссылки все равно надо конешно подюзать, я просто ввообще обходился без ссылок как то, столько тут возможностей сделать одно и тоже разными способами...
вообще если я правильно понял архитектуру прог, где употреблюятся жесткие ссылки, то я юзал для замены сначала модуль IPC::Shaerable, а дальше забил и теперь посылаю исключения. Если толко я правильно понял, что жесткие ссылки нужны для того, чтобы обращаясь к разным переменных получать одинаковые значения. Короче, не шарящий чел.
"Здесь `$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";
}
To vilfred. Скажу сразу для ясности, что каким-то образом обижать
или смеяться над тобой и в мыслях не было. Более того, высмеивание
тех, кто просто не знает каких-то возможности языка, считаю
идиотизмом. Молчу уж о том, что в Перле я пока ну очень слаб.
Ладно, далее.
>> @{$res[$i]} = @a[$begin..$end] if $i!=2;
>> "Здесь `$res[$i]' - ссылка на _анонимный_ массив, который
>> заполняется элементами из массива @a." - стой, погоди, я чето
>> не вдумался, это вроде как массив массивов и он не анонимный
>> потому, что поименован индексом. Или я че не понял в этой жизни?
>> Конструкция @{} нужна, чтобы к переменной $rr[$i] обращаться как к
$res[$i] - это _скаляр_, о чем уже говорит знак доллара вначале.
В Perl'овых массивах, как и хешах, элементами могут быть _только_
скаляры. Еще раз ссылаюсь на perdoc perlreftut - там предельно
просто и доступно все написано. Ты на С никогда не писал? Прямая
аналогия, это просто указатель на массив. Конструкция @{$чтонибудь}
велит интерпретировать величину $чтонибудь как указатель. То есть
в $что-нибудь находится адрес ячейки памяти, где этот массив
валяется (первый его элемент). Вот и все. И имя этому массиву
присваивать не обязательно, главное - адрес есть.
"То есть в $что-нибудь находится адрес ячейки памяти, где этот массив
валяется (первый его элемент)." - постой, но все равно ведь числовое извлечение происходит, по номеру элемента массива (ты для того чтобы извлечь данные по 10 му элементу не к абстрактной ссылке обращаешься, а пишешь 10). Да, с некоторой точки зрения там все есть ссылка (хотябы потому что не ref оно само ответило), я даже думаю, что строчка $a=5 механически тоже ссылка...
Я на сях вообще не писал, потому у меня немного иной взгляд на некоторые вещи... ты вон даже вместо принт пишешь принтф, я не сишник вообще, поэтому некоторые мои слова звучат немного не так, ну штож, такива жиссььь :)
меня тут удивило недавно, что это дает четыре без всяких %d или что там надо писать: perl -e '$xx="2*2"; printf eval $xx'
>> Да, с некоторой точки зрения там все есть ссылка (хотябы потому
>> что не ref оно само ответило), я даже думаю, что строчка $a=5
>> механически тоже ссылка...
Именно! :-)
>> ты вон даже вместо принт пишешь принтф
Ну когда нужон красивый вывод, то да. А вообще как раз НЕ хочу чтоб
выглядело похожим на С. Иначе зачем я тогда с него слезал :-)
по поводу красивого вывода такой код у меня есть:
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;
}