Search     or:     and:
 LINUX 
 Language 
 Kernel 
 Package 
 Book 
 Test 
 OS 
 Forum 
 iakovlev.org 
 Languages
 С
 GNU С Library 
 Qt 
 STL 
 Threads 
 C++ 
 Samples 
 stanford.edu 
 ANSI C
 Libs
 LD
 Socket
 Pusher
 Pipes
 Encryption
 Plugin
 Inter-Process
 Errors
 Deep C Secrets
 C + UNIX
 Linked Lists / Trees
 Asm
 Perl
 Python
 Shell
 Erlang
 Go
 Rust
 Алгоритмы
NEWS
Последние статьи :
  Тренажёр 16.01   
  Эльбрус 05.12   
  Алгоритмы 12.04   
  Rust 07.11   
  Go 25.12   
  EXT4 10.11   
  FS benchmark 15.09   
  Сетунь 23.07   
  Trees 25.06   
  Apache 03.02   
 
TOP 20
 MINIX...3057 
 Solaris...2933 
 LD...2905 
 Linux Kernel 2.6...2470 
 William Gropp...2182 
 Rodriguez 6...2014 
 C++ Templates 3...1945 
 Trees...1938 
 Kamran Husain...1866 
 Secure Programming for Li...1792 
 Максвелл 5...1710 
 DevFS...1694 
 Part 3...1684 
 Stein-MacEachern-> Час...1632 
 Go Web ...1625 
 Ethreal 4...1619 
 Arrays...1607 
 Стивенс 9...1603 
 Максвелл 1...1592 
 FAQ...1538 
 
  01.01.2024 : 3621733 посещений 

iakovlev.org

Массивы

 Массивы - это один из типов данных в перл, а вообще массивы есть практически 
 в любом языке программирования. Если скаляр - это переменная, у которой есть
 какое-то конкретное значение, то массив - это список каких-либо элементов. 
 Например (5, "Hacked", $site) это список который содержит цифру, строку и переменную.
 
  Чтобы создать массив, надо просто присвоить ему какое-либо значение, например:
 	@deface=qw ( Hacked by Me );
 Эта строчка создаст массив с 3 элементами. Оператор qw позволяет записывать
 элементы массива без кавычек.
 
  Чтобы вывести содержимое массива на экран, надо использовать тот же оператор,
 что и для обычных переменных:
 	print "@array";
 
  Если вам надо напечатать только какие-то отдельные элементы, то нужно 
  воспользоваться индексами, например, создадим массив @lang:
 	@lang=qw ( Perl PHP C++ Java Asm );
 У каждого из элементов массива есть свой порядковый номер, причём отсчёт 
 начинается с 0:
   0   1   2    3   4
   Perl PHP C++ Java Asm
 Итак, если надо распечатать, например только 1 и 3 элементы массива, то:
 	print $lang[1];
 	print $lang[3];
 
  Один из способов преобразования скаляра в массив - оператор split. 
  Рассмотрим эту строку:
 	@words=split(//, "Hacked by me");
 Этот оператор берёт строку Hacked by me, делит её по словам
 (для этого служит шаблон //, о шаблонах - позже) и помещает слова в массив,
 причём каждое слово содержится в отдельном элементе массива.
 
  Раасмотрим пример : пусть имеется массив , в котором каждый элемент имеет имя .
 Задача - как по имени элемента получить его значение ?
 	%form_test = ('a1' => 11 ,'a2' => 22 ,'a3' => 33 );
 	$name="test";
 	$tmp = eval "\\\%form_$name";
 	$key_val = $$tmp{"a2"};
 
  В следующем примере организуем массив , элементами которого являются 
  другие массивы , причем нефиксированного размера : 
 	@a=(["a","b","c"],["d","e"],["f"]);
 	foreach $b (@a){
 	    foreach $c (@$b){
 		print "$c\n";
 	    }
 		print "====\n";
 	}
 	$z=$a[1][1];
 	print "--$z\n";
 
  Чтобы обьединить 2 массива в один массив :
 	@array1 = (1, 2, 3);
 	@array2 = (4, 5, 6);
 	@bigarray = (@array1, @array2);
 
 Чтобы выделить часть массива :
 	@array = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
 	@array2 = @array[2..3];
 
 	
  В следующем примере дан плоский массив. 
  Задача - увеличить значение каждого элемента на 1 :
 	my @arr = (1, 2, 3, "a");
 	print "@arr\n";	
 Без использования индекса :
 	foreach (@arr){
 	  ++$_;
 	}
 	print "@arr\n";
 	foreach my $current (@arr){
 	  ++$current;
 	}
 	print "@arr\n";
 С использованием индекса :
 	foreach (0..@arr-1){
 	  ++$arr[$_];
 	}
 	print "@arr\n";
 	foreach my $index (0..@arr-1){
 	  ++$arr[$index];
 	}
 	print "@arr\n";
 	foreach (0..$#arr){
 	  ++$arr[$_];
 	}
 	print "@arr\n";
 
 	  my $index=0;
 	  foreach (@arr){
 	    ++$arr[$index]; #  или ++$_;
 	    ++$index;
 	  }
 	  print "@arr\n";
 
  В следующем примере имеется неотсортированный массив с повторяющимися значениями .
 	@taxon = (1,3,5,5,5,3,1,5,5,5,5,3,3,7,9,10);
 Задача - оставить только уникальные значения .
 Первый вариант - простой перебор :
 	my $i=0;
 	while(defined $taxon[$i])
 	{
 		my $n = $i + 1;
 		while (defined $taxon[$n])
 		{
 			if ($taxon[$i] == $taxon[$n]) { splice(@taxon, $n, 1); }
 			else { $n++; }	
 		}
 		$i++;
 	}
 А вот более изящное решение :
 	%z = map { $_=>0 } @taxon;
 	@taxon = keys %z;
 И еще один вариант :
 	@unique = grep { ++$count{$_} < 2 } qw(a b a c d d e f g f h h);
 
  Сортировка числового массива по возрастанию :   
 	@array = (8, 2, 32, 1, 4, 16);
 	print join(' ', sort { $a <=> $b } @array), "\n";
 
  ASCII-сортировка
 	@languages = qw(fortran lisp c c++ Perl python java);
 	print join(' ', sort @languages), "\n";
 
  Сортировка по алфавиту :
 	use locale; 
 	@array = qw(ASCII ascap at_large atlarge A ARP arp);
 	@sorted = sort { ($da = lc $a) =~ s/[\W_]+//g;
                  ($db = lc $b) =~ s/[\W_]+//g;
                  $da cmp $db;
                } @array;
 	print "@sorted\n";
 
  Реверс-сортировка :
 	sort { $b <=> $a } @array;
 
  Удаление из списка :
 	@list = splice @array, $from, $length, список
 
  В следующем примере нужно распечатать элементы , которые встречаются в 
  массиве 2 раза :
 	 @crops = qw(wheat corn barley rice corn soybean hay 
 	            alfalfa rice hay beets corn hay);
 	@duplicates = grep { $count{$_} == 2 } 
 	              grep { ++$count{$_} > 1 } @crops;
 	print "@duplicates\n";
 
 
  Имеются 2 параллельных массива - из номеров страниц и примечаний к этим страницам.
 Отпечатать оба массива , отсортировав их по номерам :
 	@page = qw(24 75 41 9);
 	@note = qw(p.24-text p.75-text p.41-text p.9-text);
 	@note_sorted = @note[sort { $page[$a] <=> $page[$b] } 0..$#page];
 
  Сортировка массива по убыванию :
 print "по убыванию: ",
 join(" ", sort { $b <=> $a } 3,4,1,5,9,7),"\n";
 
  Переворачивание массива :
 	@stooges = (3,4,2,5,6,7,8);
 	@segoots = reverse(@stooges); 
 
  Разбиение строки на набор слов по пробелу :
 	$str = "I'm not as think as you stoned I am";
 	@words = split (/ /, $str);
 
  Добавление элемента в массив :
 	@array = ("Quarter","Dime","Nickel");
 	push(@array, "Penny"); 
  Вставка-сдвиг на начальную позицию :
 	unshift(@array, "Dollar");
  Удаление последнего элемента :	
 	pop(@array);
  Удаление первого элемента :
 	shift(@array);
  Удаление элемента с индексом index : 
 	delete $array[index]
 
  В следующем примере имеется база клиентов , в которой нужно найти 
  одного с критериями city , music :
 	@client = (
 { name      => "serg",     city      => "Москва",      music     => "рок"     },
 { name      => "alex",     city      => "Москва",      music     => "джаз"    },
 { name      => "john",     city      => "Киев",        music     => "рок"     },
 { name      => "smith",    city      => "Москва",      music     => "рок"     }
 	);
 	%query = ( city => 'Москва', music => 'рок' );
 	@res = findRestaurants(\@client, \%query);
 	print "$res[0]->{name}\n";
 	sub findRestaurants {
 	    my ($client, $query) = @_;
 	    return grep {
 	        $query->{city} ?
 	            lc($query->{city}) eq lc($_->{city}) : 1
 	        and $query->{music} ? $_->{music} : 1
 	    } @$client;
 	}
 
  Пример maximal obfuscation :
 	print map( { chr }
            ('10611711511603209711011111610410111' .
            '4032112101114108032104097099107101114')
            =~ /.../g
          ), "\n";
 
  Транспонирование матрицы :
 	@matrix = ( [1, 2, 3], [4, 5, 6], [7, 8, 9] );
 	foreach $xyz (@matrix) {
 	    print "$xyz->[0]  $xyz->[1]  $xyz->[2]\n";
 	}
 	@transposed =     map { $x = $_;
 	          [ map { $matrix[$_][$x] } 0 .. $#matrix ];
 	        } 0 .. $#{$matrix[0]};
 	print "\n";
 	foreach $xyz (@transposed) {
 	    print "$xyz->[0]  $xyz->[1]  $xyz->[2]\n";
 	}
 
  Распечатка первых простых чисел , меньших 1000 :
 	foreach $num (1 .. 1000) {
 	    @expr = map { '$_ % ' . $_ . ' &&' } 2 .. int sqrt $num;
 	    if (eval "grep { @expr 1 } $num") { print "$num " }
 	}
  То же самое :
 	CANDIDATE: foreach $num (1 .. 1000) {
 	    foreach $factor (2 .. int sqrt $num) {
 	        unless ($num % $factor) { next CANDIDATE }
 	    }
 	    print "$num ";
 	}
 
  Следующий пример показывает , как в процедуру передать 2 ссылки на 2 массива 
  и найти сумму членов этих массивов с одинаковыми индексами :
 	@array1 = (1, 3, 5);
 	@array2 = (2, 4, 6);
 	$ref1 = \@array1;
 	$ref2 = \@array2;
 	@sum = &array_adder($ref1, $ref2);
 	print "\@sum = (", join(',',@sum), ")\n";
 	sub array_adder{
 	my($ref1, $ref2) = @_;
 	my $i = 0;
 	my @sum;
 	for($i = 0; $i <= $#{$ref1} ; $i++){
 		$sum[$i] = ${$ref1}[$i] + ${$ref2}[$i];
 	}
 	return @sum;
 	}
 
 
 Пример : имеется матрица 3х3.
 Нужно отсортировать ее по 2-му столбцу .
 Вариант решения :
 @a = ( [4, 5, 6],
        [7, 8, 9],
        [1, 2, 3]
          );
 for ($i=0;$i<2;$i++){
  for ($j=1;$j<3;$j++) {
    if ($a[$i][1]>$a[$j][1])   { # делаем swap
        $swap0=$a[$i][0];
        $swap1=$a[$i][1];
        $swap2=$a[$i][2];
        $a[$i][0]=$a[$j][0];
        $a[$i][1]=$a[$j][1];
        $a[$i][2]=$a[$j][2];
        $a[$j][0]=$swap0;
        $a[$j][1]=$swap1;
        $a[$j][2]=$swap2;
    } }}
 
 
 

Ссылки

До perl5 в перле было всего три (основных) типа данных и имя переменной полностью определяло, данные какого типа она хранит $x - хранит ЗHАЧЕHИЕ (число или строку) @x - хранит список ЗHАЧЕHИЙ %x - хранит список пар строка->ЗHАЧЕHИЕ В perl5 всё осталось также, только понятие ЗHАЧЕHИЯ было расширено - теперь это может быть ССЫЛКА на массив или хеш. очень важная тонкость - в отличие от самого массива или хеша, ССЫЛКА на них является скаляром: @a = (1,2); $a = [ (1,2) ]; # квадратные скобки превращают массив/хеш в ССЫЛКУ на массив %b = (1=>2); $b = { (1=>2) }; # фигурные скобки превращают массив/хеш в ССЫЛКУ на хеш Обратите внимания - круглые скобки используются только для группировки, а квадратные и фигурные являются ОПЕРАТОРОМ, превращающим СОСТАВHОЕ ЗHАЧЕHИЕ в ССЫЛКУ. Внутри []/{} круглые скобки обычно опускают, я привёл их лишь для удобства понимания единственной существенной разницы между этими действиями Теперь несложно сконструировать массив массивов: @c = ( [1,2], [2], [3,4,5] ); На самом деле, конечно, это массив ССЫЛОК на массивы. но к его элементам можно обращаться, не задумываясь об этом - $c[0][1] Или создадим хеш хешей: %d = ( C=> {Speed=>Good, Readability=>Bad}, Perl=>{Speed=>hmmm} ); Опять же, $d{Perl}{Speed} будет работать Если же вы и внешние круглые скобки замените на []/{}, то опять получите скаляр, и его надо будет присваивать тоже скаляру: $e = [ [1,2], [3,4] ]; # ССЫЛКА на массив, состоящий из ССЫЛОК на массивы Поскольку перловые функции обычно ожидают "развёрнутый" массив/хеш, пользоваться таким скаляром будет неудобно. да и к элементам его доступ неочевиден - $e->[0][1]. собственно, "->" - оператор разыменования ССЫЛОК, и для доступа к элементам @c он тоже используется, но перл вставляет его неявно: $c[0][1] эквивалентно $c[0]->[1]. То есть, $c[0] возвращает нам ССЫЛКУ на массив, стрелка её разыменовывает (превращает ССЫЛКУ в массив) и затем второе индексирование "[1]" возвращает нам элемент этого массива. $e->[0][1] на самом деле работает как $e->[0]->[1]: разыменовываем, берём элемент, снова разыменовываем, и снова берём элемент. с массивами хешей, и со сколь угодно более сложными структурами данных всё точно также. разумеется, их можно произвольно смешивать: $a = [ 1, [2,3], {a=>b}, [[4,5]] ]; 1 == $a->[0] 2 == $a->[1][0] b == $a->[2]->{a} == $a->[2]{a} 5 == $a->[3][0][1] Операторы []/{} создают КОПИИ переданных им ЗHАЧЕHИЙ. если вы хотите вместо этого получить ССЫЛКУ на ТЕ ЖЕ данные, используйте оператор "\". кстати, эти операторы можно комбинировать: @a = (1,2); @b = (3,4); @c = ( [@a], [@b] ); # @c содержит (ССЫЛКИ на) копии массивов a и b @d = ( \@a, \@b ); # @d содержит ССЫЛКИ на массивы a и b @e = ( [\@a, \@b], [[@a], [@b]] ); @e - трёхмерный массив, $e[0][0][$i] эквивалентно $a[$i] $e[0][1][$i] эквивалентно $b[$i] $e[1][0][$i] содержат копии $a[$i] $e[1][1][$i] содержат копии $b[$i] Т.е. теперь присваивания $a[$i] изменят также ЗHАЧЕHИЯ $d[0][$i] и $e[0][0][$i] и наоборот. ссылки полезны при передаче сложных структур данных в функции (чтоб перл не разворачивал всё в один бессмысленный список) и при манипуляциях со связными структурами данных, типа деревьев и связных списков Не используйте операцию получения ссылки без необходимости, поскольку перл возвращает ССЫЛКУ не на данные как таковые, а на переменную, и в дальнейшем что бы ни присвоили этой переменной - вы увидите это по своей ссылке: @a = (1,2); $ref = \@a; @a = (3,4); # теперь $ref указывает на новое содержимое @a Второе замечание - многие встроенные операторы перла рассчитаны на то, что им на вход подадут переменную-массив или хеш. Но никак не ССЫЛКУ. для того, чтобы превратить одно в другое, используются конструкции @{...} и %{...}: push @{$c[0]}, 0; # $c[0] - ССЫЛКА на массив, @{$c[0]} - сам массив %d = ( C=> {Speed=>Good, Readability=>Bad}, Perl=>{Speed=>hmmm} ); print keys %{$d{C}} # $d{C} - ССЫЛКА на хеш, %{$d{C}} - сам хеш и когда нужно вывести сами новости в количестве $n штук на страничку. Ссылка - это скаляр , который указывает на массив или хэш или что-то еще . Одна из форм обращения со ссылками - обратный слэш . Если слева от переменной мы ставим \ , мы получаем ссылку на эту переменую . $aref = \@array; # ссылка на @array $href = \%hash; # ссылка на %hash Далее ссылку можно копировать как скаляр : $xy = $aref; # ссылка на @array $p[3] = $href; # ссылка на %hash $z = $p[3]; # ссылка на %hash Это был пример того , как сделать ссылку на переменную с именем . А можно ли сделать ссылку на переменную , у которой нет имени ? В перле это делается с помощью анонимных переменных . [ ITEMS ] - форма создания анонимного массива . { ITEMS } - форма создания анонимного хэша . $aref = [ 1, "foo", undef, 13 ]; # $aref - ссылка на массив $href = { APR => 4, AUG => 8 }; # $href - ссылка на хэш Ссылка , которую мы получили во втором варианте , ничем не хуже той , которую мы получили в первом случае . $aref = [ 1, 2, 3 ]; @array = (1, 2, 3); $aref = \@array; Как использовать ссылки ? Для начала ссылку можно присвоить какой-нибудь переменной , после чего : @a @{$aref} сохраним ссылку reverse @a reverse @{$aref} перевернем массив $a[3] ${$aref}[3] возьмем элемент массива $a[3] = 17; ${$aref}[3] = 17 изменим элемент массива Видно , что с массивом можно оперировать 2-мя способами одинаково , дело только за вкусом . В случае с хэшем картина аналогичная : %h %{$href} сохраним ссылку keys %h keys %{$href} получить ключи из хэша $h{'red'} ${$href}{'red'} элемент хэша $h{'red'} = 17 ${$href}{'red'} = 17 назначить элемент ${$aref}[3] - довольно неприглядный синтаксис для элемента массива , куда круче $aref->[3] Аналогично для хэша : $href->{red} Следующий пример : @a = ( [1, 2, 3], [4, 5, 6], [7, 8, 9] ); @a - массив из 3-х элементов , каждый из которых представляет из себя ссылку на другой массив . Тут мы подходим к оперированию в перл таким понятием , как 2-мерный массив : $a[1]->[2] равен 6 , $a[0]->[1] равен 2. В общей форме это как $a[ROW]->[COLUMN] . Кстати говоря , вместо $a[1]->[2] мы можем написать $a[1][2] - это то же самое . Следующий пример : имеются записи в базе данных "город-штат" Chicago, Illinois New York, New York Albany, New York Springfield, Illinois Trenton, New Jersey Evanston, Illinois Нужно отсортировать по принципу : Illinois: Chicago, Evanston, Springfield. New Jersey: Trenton. New York: Albany, New York. Решение : 1 while (<>) { 2 chomp; 3 my ($city, $state) = split /, /; 4 push @{$table{$state}}, $city; 5 } 6 7 foreach $state (sort keys %table) { 8 print "$state: "; 9 my @cities = @{$table{$state}}; 10 print join ', ', sort @cities; 11 print ".\n"; 12 } В 4-й строке формируется хэш %table, эта строка аналогичнв push @array, $city; В 9-й строке идет извлечение городов для каждого штата , она аналогична строке @cities = @array; Подведем некоторые итоги по ссылкам :
  • Ссылки можно делать на что угодно , включая скаляры , функции , другие ссылки .
  • Фигурные скобки по возможности нужно опускать ,например : @$aref - это то же самое , что и @{$aref}, и $$aref[1] - то же , что и ${$aref}[1].
  • Для проверки того , является ли переменная ссылкой , нужно использовать фунцию ref . Она должна вернуть true .Для хэша она возвращает HASH , для массива - ARRAY .
Оставьте свой комментарий !

Ваше имя:
Комментарий:
Оба поля являются обязательными

 Автор  Комментарий к данной статье
zizmo
  Очень приятно. Сжато и емко. Нашел что искал. Спасибо.
2007-09-04 16:17:10