Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Perl: Общие вопросы > удалить элемент с массив хєша


Автор: gcc 19.3.2009, 04:13
не получается удалить или проверить не пуской ли массив-хэшей, то есть при проверке не пустой ли массив оно не адекватно как-то работает... if ($loop_data) {  или так if ($#{$loop_data}) { 

где может быть ошибка как удалить элемент массива и хэши в нем?

пример:

Код

    $sth->execute($args[0]);
    my $loop_data;
        push @{$loop_data}, $_ while $_ = $sth->fetchrow_hashref();
    $sth->finish();      
           
              foreach $_ (@{$loop_data}) {
            
            if ($_->{active_co} == 0 && ($_->{id_un} != $c->user->{user}->{id} 
                     || !$c->check_user_roles('moder_se') )            )  {           
            $_->{no_show_co} = 1;            
            }
            
            if ($_->{id_un} == $c->user->{user}->{id} 
                     || $c->check_user_roles('moder_se')             )  {           
            $_->{modering_co} = 1;            
            }
            
            if ($_->{hiden_co} == 1 && ($_->{id_un} != $c->user->{user}->{id} 
                     || !$c->check_user_roles('moder_se') )            )  {           
            $_->{no_show_co} = 1;
             
            }
                        
            if ($_->{hiden_g_co} == 1 && $c->user_exists() == 0  )  {           
            $_->{no_show_co} = 1;
  }
             $_->{close_se} = $_->{close_se} == 1 ? '1' : undef;    
             $_->{active_co} = $_->{active_co} == 0 ? '1' : undef;    
             
             $_->{edit_active_co} = $c->check_user_roles('moder_co') ? '1' : undef;                
             $_->{edit_close_co} = $c->check_user_roles('moder_co') ? '1' : undef;         
             
             # $_ = undef;
              # splice @{$loop_data}, $_, 10;
              
              # use Data::Dumper;   
              # print Dumper($_);           
           }
           
        for my $loopindex (0..$#{$loop_data}) 
       {

        for my $key (keys %{@{$loop_data}[$loopindex]})
              {
             #print "$key => @{$loop_data}[$loopindex]{$key},";
      
             }
       splice @{$loop_data}, $loopindex;
       }
                  use Data::Dumper;   
             print Dumper($loop_data);    
           
     #my $t = scalar @{$loop_data};
     #     print $t;
          
    if ($loop_data) { 
             $c->stash->{messages} = $loop_data;
    } else {
         $c->stash->{messages_error} = 1;
    }

Автор: pompei 19.3.2009, 05:42
а следующий код
Код

for my $loopindex (0..$#{$loop_data}) 
       {
        for my $key (keys %{@{$loop_data}[$loopindex]})
              {
             #print "$key => @{$loop_data}[$loopindex]{$key},";
      
             }
       splice @{$loop_data}, $loopindex;
       }
                  use Data::Dumper;   
             print Dumper($loop_data);    

вообще какаято лажа. Вы  когда делаете  splice @{$loop_data}, $loopindex; то $#{$loop_data} уменьшается на 1, $loopindex увеличивается на 1, т.е. в оконцове все четные элементы в массиве останутся а нечётные распечатуются и удалятся.

 if ($loop_data) { } - всегда будет истина, даже если тот массив, на который ссылается переменная, будет пустой.
правильно будет так
if (scalar(@{$loop_data}) == 0) {...} #т.е. "если количество элементов в массиве равно нулю"
здесь оператор scalar необязателен, но для спокойствия пусть стоит
ПРИМЕЧАНИЕ:  если массив используется в скалярном контексте, то возвращается количество элементов в мессиве

если вам просто надо очистить массив то следайте так
$loop_data = [];
а если на этот массив ещё кто-то ссылается и ихние ссылки тоже должны быть очищены, то вот так
@{$loop_data} = ();

Незабывайте что есть ещё такие функции
shift @{$loop_data} - удалить из массива первый элемент и вернуть его
pop @{$loop_data} - удалить из массива последний элемент и вернуть его

Автор: gcc 19.3.2009, 08:27
как тогда правильно удалить конкретный элемент массива при переборе в завсисмости от условия? и проверить не пустой ли массив? (у меня массив с одним значением у котрого хеши, я удалил эти хэши, но а массив стал не пустой)

UPD: я поменял это @{$loop_data}, на это @loop_data без ссылки написал - вроде бы работает! 
если есть вариант более оптимальный, то скажите..

Автор: pompei 19.3.2009, 13:40
Код

use warnings;
use strict;



my $arr = [1,5,4,7,6,8,9,4,-8,5,6,7,8,-8,3,45,-8,-8,2,5,76,-8];
#my $arr = [-8,-8,-8,-8,-8,-8,-8,-8,-8,-8,-8,-8,-8,-8,-8,-8,-8,-8,-8,-8,-8,-8,-8,-8,-8,-8,-8,-8,-8,-8,-8,-8,-8,-8,-8,-8];

# Вот как можно из массива удалить все -8 (т.е. все элементы соответствующие некому условию)
my $index = 0;
while ( $index < scalar @$arr ) {
   my $element = $arr->[$index];
   if ($element == -8) {
       splice @$arr, $index;
       # $index увеличивать не нужно, т.к. он уже указывает 
       # на следующий, который встал на мето текущего
   } else {
       $index++;
       # ну а теперь нужно
   }
}

if (0 == scalar @$arr) {
    print "Ого все элементы в массиве удалили";
}


Автор: amg 19.3.2009, 16:00
Цитата(gcc @  19.3.2009,  08:27 Найти цитируемый пост)
как тогда правильно удалить конкретный элемент массива при переборе в завсисмости от условия? 
Напрашивается воспользоваться grep:
Код
$arr = [ grep {$_ != -8} @$arr ];
Но это требует больше памяти и редактирование массива получается не "по месту". Зато понятно и коротко.

Автор: klem4 19.3.2009, 18:08
Код

my @arr = (-8, 1, 2, 3, -8, 4, -8);
  for ( my $i = $#arr; $i + 1; ) {
    @arr = @arr[0..$i - 1, $i + 1..$#arr], next if $arr[$i] == -8;
    $i--;
  }

Автор: pompei 20.3.2009, 05:06
Цитата(gcc @  19.3.2009,  08:27 Найти цитируемый пост)
к
Код
$arr = [ grep {$_ != -8} @$arr ];
Но это требует больше памяти и редактирование массива получается не "по месту". Зато понятно и коротко.

Ну а если на этот массив ещё кто-то ссылается, то в таком случае у того останется старый массив

Кстати есть ещё вот такой синтаксис:
Код
$arr = [ grep $_ != -8, @$arr ];

Автор: klem4 20.3.2009, 08:21
Потестировал немного, на массивах до 10000 при большом кол-ве удалений цикл быстрее грепа, а при больших чем 10000 масивах греп рвет.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)