Как стать автором
Обновить

Slice, или очень полезные ломтики в Perl

Время на прочтение2 мин
Количество просмотров1.4K
Решая задачи реального мира нам постоянно приходится работать со списками данных. И самые счастливые в этой деятельности — Perl-программисты :)

Это все потому, что для работы с частью массива или хеша у нас есть удобный slice. Slice — это не оператор, это принцип обработки данных, когда от большого объекта отрезается кусочек.
Проще показать:

my @arr = (1, 3, 5, 7, 9);
my @arr_slice = @arr[2..4]; # (5, 7, 9)

my %hash = ( 'first' => 2, 'second' => 5, 'last' => 99);
my @hash_slice = @hash{'first', 'last'}; # (2, 99)


* This source code was highlighted with Source Code Highlighter.


А вот так выглядит синтаксис анонимных массивов и хешей:

my $arr_ref = [1, 3, 5, 7, 9];
my @arr_ref_slice = @{$arr_ref}[2,3]; # (5, 7)

my $hash_ref = {'first' => 2, 'second' => 5, 'last' => 99};
my @hash_ref_slice = @{$hash_ref}{'second', 'last'}; # (5, 99)


* This source code was highlighted with Source Code Highlighter.


NB. общее правило для анонимных структур —
обозначается всегда как массив, в первых скобках — ссылка на интересующий нас объект, являющийся массивом или хешем, во вторых — перечисление элементов этого объекта.

my $deep_arr = [1, [2, 3, [4, [20, 26, 28]]], 10];
my @deep_arr_slice = @{$deep_arr->[1][2][1]}[0,2]; # (20, 28)


С многомерным хешем и массивами хешей, ровно как и хешами массиво и т.д. поступаем аналогично, попробуйте сами, это совершенно несложно.

Я же перейду к другому — срезу хеша для создания нового хеша.

my @keys = ('first', 'last');
my %old_hash = ( 'first' => 2, 'second' => 6, 'last' => 99);
my %new_hash;
@new_hash{@keys} = @old_hash{@keys};
# (first => 2, last => 99)



Вуаля! Самое главное не забывать предварительно объявлять новый хеш, дальше perl сам создаст требуемые ключи и присвоит им значение из старого хеша. Всяко короче циклов. Да еще и нагляднее.

Правда, есть одна загвоздка — вот для такой структуры
my $complex_ref = [{'a' => 2, 'b' => 5}, {'a' => -4, 'b' => 8}, {'a' => 10, 'b' => -2}];

выбрать все значения 'a' и присвоить их новому массиву не получится как-то так:
my @new_complex = @{$complex_ref}[0..2]{'a'} # wrong!!! syntax error
или так:
my @new_complex = @{$complex_ref->[0..2]}{'a'}; # (-4)???!!!

Для решения этой задачки мы немного схитрим и возьмем… правильно, map!

my @new_complex = map {$_->{'a'}} @{$complex_ref}[0..2];

Ну а вот такие штуки пригодятся в реальной жизни:

my $new_complex_ref = [ map { {'a' => $_->{'a'}, 'c' => ( $_->{'b'} + 3 )} } @{$complex_ref}[0, 2] ];


Попробуйте разобраться, сложного абсолютно ничего нет. Соглашусь, что код стал чуть менее читаем, однако его «классический» вариант типа

my $classic_complex_ref;
for( my $i = 0; $i <= $#{$complex_ref}; $i++ ){ 
  next if ( $i == 1 );
  my $a_val = $complex_ref->[$i]{'a'};
  my $b_val = $complex_ref->[$i]{'b'}; 
  $b_val += 3;  
  my $hash = { 'a' => $a_val, 'b' => $b_val}; 
  push @$classic_complex_ref, $hash;
}


* This source code was highlighted with Source Code Highlighter.


слишком громоздок.

ИМХО — подробное комментирование меньшего по объему кода куда как целесообразнее кода на уровне школьных учебников без каких-то комментариев. Читать естественный язык проще, быстрее и приятнее.

PS. Пост написан из самых лучших побуждений немного осветить момент, очевидный для профи и непонятный для новичков языка.
Теги:
Хабы:
Всего голосов 11: ↑10 и ↓1+9
Комментарии8

Публикации