Модераторы: korob2001, ginnie

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Уплотнение массива, замена нескольких пустых элементов одним 
:(
    Опции темы
amg
Дата 22.3.2007, 11:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1145
Регистрация: 3.8.2006
Где: Новосибирск

Репутация: 38
Всего: 50



Нужно проделать с массивом то, что обычно делают со строками:
Код

s/^\s+//; # Удаляем пустые элементы в начале
s/\s+$//; # Удаляем пустые элементы в конце
s/\s+/ /g; # Заменяем каждую последовательность пустых элементов одним

Конечно, какой-то работающий код для массива у меня есть. Но, как обычно, интересует эффективность, в частности, можно ли обойтись без временного массива.
PM MAIL   Вверх
arto
Дата 22.3.2007, 12:26 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1495
Регистрация: 31.10.2004

Репутация: 38
Всего: 40



grep или map со splice
PM MAIL ICQ   Вверх
tishaishii
Дата 22.3.2007, 13:26 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Создатель
***


Профиль
Группа: Завсегдатай
Сообщений: 1262
Регистрация: 14.2.2006
Где: Москва

Репутация: 4
Всего: 8



Не удастся с grep. grep возвращает массив.
Надо splice и for или while.
Код
sub xgrep(&@) {
    my($sub, $arr, $size, $j, $i)=(shift, $_[0], (scalar @{+shift}) x 2, 0);
    while($j>0 && $i<$size) {
        splice @$arr, $i--, 1 unless $sub->($arr->[$i]);
        $i++;
        $j--
    }
    +$arr
}

my@arr=1..20;
xgrep{$_[0]>5 && $_[0]<10}\@arr;
print join "\n", @arr;


Это сообщение отредактировал(а) tishaishii - 22.3.2007, 13:31
PM MAIL ICQ Skype   Вверх
arto
Дата 22.3.2007, 13:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1495
Регистрация: 31.10.2004

Репутация: 38
Всего: 40



my $a = 0; grep { defined ($_) ? $a++ : splice @a,$a,1 } @a
PM MAIL ICQ   Вверх
Nab
Дата 22.3.2007, 13:49 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 582
Регистрация: 25.3.2006
Где: Kiev

Репутация: 26
Всего: 37



Можно вот так вот:
Код

my ($i, $space) = (0,0);
# пока не достигли конца массива
while ($i < @array) {
  # если елемент пустой
  if (@array[$i++]) {
    # если предыдущие были пустыми елементами, то мы их удаляем
    if ($space) {
      # откатываем индекс
      $i -= $space;
      # удаляем пустые елементы
      splice @array, $i, $space;
      # обнуляем счетчик пустых елементов
      $space = 0
    }
  } else {
    # здесь мы будем если у нас пустой елемент, 
    # мы его пропускаем, но увеличиваем счетчик...
    # чтоб обработать впоследствии
    $space++;
  }
}
# а здесь мы удаляем если в конце массива у нас пустые есть, мы то уже из цикла вышли по окончании индекса
splice @array, $i - $space, $space if $space;

Отличие то что позволяет за один раз удалить несколько елементов... не вызывая splice каждому...

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


--------------------
 Чтобы правильно задать вопрос нужно знать больше половины ответа...
Perl Community 
FREESCO in Ukraine 
PM MAIL   Вверх
amg
Дата 22.3.2007, 13:57 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1145
Регистрация: 3.8.2006
Где: Новосибирск

Репутация: 38
Всего: 50



arto, твой код просто удаляет все пустые элементы, а это не совсем то, что нужно.
PM MAIL   Вверх
Nab
Дата 22.3.2007, 14:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 582
Регистрация: 25.3.2006
Где: Kiev

Репутация: 26
Всего: 37



Проверил, работает:
Код

@array = map {if ($_) { $s=0; $_ } else {$s++?():$_}} @array;



--------------------
 Чтобы правильно задать вопрос нужно знать больше половины ответа...
Perl Community 
FREESCO in Ukraine 
PM MAIL   Вверх
arto
Дата 22.3.2007, 14:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1495
Регистрация: 31.10.2004

Репутация: 38
Всего: 40



"Нужно проделать с массивом то, что обычно делают со строками:
s/^\s+//; # Удаляем пустые элементы в начале" -- ?
PM MAIL ICQ   Вверх
Nab
Дата 22.3.2007, 14:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 582
Регистрация: 25.3.2006
Где: Kiev

Репутация: 26
Всего: 37



arto, не придирайся, smile то в начале, но не везде, да и мой код тогда неверен...
нужно тогда как для строк, три строки:
Код

# уплотняем все пустые
@array = map {if ($_) { $s=0; $_ } else {$s++?():$_}} @array;
# удаляем лидирующий, если есть
shift(@array) unless $array[0];
# и завершающий....
pop(@array) unless $array[$#array];

думаю так лучше всего будет


--------------------
 Чтобы правильно задать вопрос нужно знать больше половины ответа...
Perl Community 
FREESCO in Ukraine 
PM MAIL   Вверх
arto
Дата 22.3.2007, 14:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1495
Регистрация: 31.10.2004

Репутация: 38
Всего: 40



так что удалять-то надо?
PM MAIL ICQ   Вверх
Nab
Дата 22.3.2007, 14:34 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 582
Регистрация: 25.3.2006
Где: Kiev

Репутация: 26
Всего: 37



Цитата(arto @  22.3.2007,  14:31 Найти цитируемый пост)
так что удалять-то надо?

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



--------------------
 Чтобы правильно задать вопрос нужно знать больше половины ответа...
Perl Community 
FREESCO in Ukraine 
PM MAIL   Вверх
tishaishii
Дата 22.3.2007, 14:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Создатель
***


Профиль
Группа: Завсегдатай
Сообщений: 1262
Регистрация: 14.2.2006
Где: Москва

Репутация: 4
Всего: 8



Что-то не видно оно.
Вот
Код
BEGIN {$SPACE="\t\r\n "}
sub unsignificantChar {+1==length $_[0] && -1!=index $SPACE, $_[0]}
sub trim {
    my($size, $arr, $i, $j)=(scalar @{$_[0]}, shift);
    for(($bool, $i)=1; $i<$size && $bool; $i++) {
        last unless &unsignificantChar($arr->[$i]);
        $arr->[$i]=()
    }
    for($j=$size-1; $j>$i; $j--) {
        last unless &unsignificantChar($arr->[$j]);
        $arr->[$j]=()
    }
}

my@arr=("\n", "\n", "\n", 1, 2, 3, "\n", "\n", "\n");
&trim(\@arr);
print '[', @arr, ']';

PM MAIL ICQ Skype   Вверх
Nab
Дата 22.3.2007, 15:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 582
Регистрация: 25.3.2006
Где: Kiev

Репутация: 26
Всего: 37



Тут, думаю стоит уточнить, что имеется ввиду под "пустым" элементом. Пробельные символы, определенность елемента, или еще что, и уже подставлять необходимое сравнение в наши варианты...


--------------------
 Чтобы правильно задать вопрос нужно знать больше половины ответа...
Perl Community 
FREESCO in Ukraine 
PM MAIL   Вверх
amg
Дата 22.3.2007, 15:37 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1145
Регистрация: 3.8.2006
Где: Новосибирск

Репутация: 38
Всего: 50



Цитата(Nab @  22.3.2007,  15:08 Найти цитируемый пост)
Тут, думаю стоит уточнить, что имеется ввиду под "пустым" элементом. 
Подойдет что угодно. Предлагаю для опреленности считать пустым элементом массива элемент, состоящий из символа "0" (ноль). Предлагаю также считать, что ведущих и ведомых нулей в массиве нет (их удалить несложно). Т.е., например, из 
('a', '0', 'b', '0', '0', 'c', '0', '0', '0', 'd')
должно получиться
('a', '0', 'b', '0', 'c', '0', 'd')

ЗЫ Господа! Примеры кода появляются быстрее, чем я успеваю в них разобраться, так что не обессудьте, сравнивать буду уже только завтра (а то у нас в Новосибирске дело к ночи).

PM MAIL   Вверх
tishaishii
Дата 23.3.2007, 01:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Создатель
***


Профиль
Группа: Завсегдатай
Сообщений: 1262
Регистрация: 14.2.2006
Где: Москва

Репутация: 4
Всего: 8



Таак.
Что-то мне уже кажется, что надо удалять "пустые символы" не только по краям, но и везде, в середине удалять дубликаты?
Ну так задача гораздо упрощается.
Код
BEGIN {$SPACE="\t\r\n0 "}
sub unsignificantChar {+1==length $_[0] && -1!=index $SPACE, $_[0]}
sub trim {
    my($arr, $i, $count)=shift;
    undef while $i<@$arr && &unsignificantChar($arr->[$i++]);
    splice @$arr, 0, --$i;$i--;
    while($i<@$arr) {
        if(&unsignificantChar($arr->[$i++])) {
            $count++
        } else {
            splice @$arr, $i---$count, $count-1 if $count>1;
            $count=0
        }
    }
    splice @$arr, $i-$count
}
my@arr=qw(0 0 0 1 0 3 2 0 0 3 0);
&trim(\@arr);
print map{'['.$_.']'}@arr;


Это сообщение отредактировал(а) tishaishii - 23.3.2007, 01:20
PM MAIL ICQ Skype   Вверх
amg
Дата 23.3.2007, 09:04 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1145
Регистрация: 3.8.2006
Где: Новосибирск

Репутация: 38
Всего: 50



tishaishii, твой код работает не совсем так, как я имел в виду. Например,
a 0 b 0 0 0 0 0 0 0 0 0 c c 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 d e
превращается в 
a 0 b 0 c c 0 0 0 0 0 0 0 d e
а я хочу получить
a 0 b 0 c c 0 d e
PM MAIL   Вверх
arto
Дата 23.3.2007, 10:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1495
Регистрация: 31.10.2004

Репутация: 38
Всего: 40



my ($a,$b) = (0,0); map { defined($_) ? ($a++,$b=0) : ($b++&&splice@a,$a++,1) } @a;
defined($a[0])||splice@a,0,1; defined($a[$#a])||splice@a,$#a,1;
PM MAIL ICQ   Вверх
amg
Дата 23.3.2007, 10:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1145
Регистрация: 3.8.2006
Где: Новосибирск

Репутация: 38
Всего: 50



Первые результаты тестирования.
Относительное время обработки массива:
Код

                     Nab   me    me1
------------------------------------
Разреженный массив   2.0   2.9   1.0
Плотный массив       4.3   6.1   3.0
Для меня оказалось совершенной неожиданностью, что (преобразование массива в строку)-(регулярное выражение)-(обратное преобразование строк в массив) работает быстро.

Код

# Очень мне понравился этот код!
sub Nab {
  my $s;
  return map {if ($_) { $s=0; $_ } else {$s++?():$_}} @_;
}

# Ужасно. Мне стыдно.
sub me {
  my @a = @_;
  my (@b, $curr, $prev);
  $prev = shift @a;
  push @a, '0';
  while (defined($curr = shift @a)) {
    next unless ($prev or $curr);
    push @b, $prev;
    $prev = $curr;
  }
  return @b;
}

# Самое тупое решение. Удивительно, но и самое быстрое.
sub me1 {
  my $s = join ':', @_;
  $s =~ s/(:0){2,}//g;
  return split ':', $s;
}


PM MAIL   Вверх
amg
Дата 23.3.2007, 11:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1145
Регистрация: 3.8.2006
Где: Новосибирск

Репутация: 38
Всего: 50



Цитата(arto @  23.3.2007,  10:05 Найти цитируемый пост)
my ($a,$b) = (0,0); map { defined($_) ? ($a++,$b=0) : ($b++&&splice@a,$a++,1) } @a;defined($a[0])||splice@a,0,1; defined($a[$#a])||splice@a,$#a,1;

arto, у меня, к сожалению, не получилось, чтобы твой код выдал то, что я ожидаю. 
Пробовал на массиве 
Код

@a = ('a',undef,undef,undef,undef,undef,undef,'b');


Это сообщение отредактировал(а) amg - 23.3.2007, 11:15
PM MAIL   Вверх
amg
Дата 23.3.2007, 11:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1145
Регистрация: 3.8.2006
Где: Новосибирск

Репутация: 38
Всего: 50



Попробовал на реальной задаче (когда элементы массива не одно-, а многосимвольные). Вариант с преобразованием массива в строку здесь здорово проигрывает остальным.
PM MAIL   Вверх
Nab
Дата 23.3.2007, 12:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 582
Регистрация: 25.3.2006
Где: Kiev

Репутация: 26
Всего: 37



ну вот такой уплотненный код для уплотнения массива получился smile

Код

sub compress {
  my $s;
  @_ = map {$_?($s=0 or$_):$s++?():$_} @_;
  $_[0]||shift(@_);
  $_[$#_]||pop(@_);
  return @_
}


Как пустые элементы подразумевается или undef или 0 или строка нулевой длины

Это сообщение отредактировал(а) Nab - 23.3.2007, 12:20


--------------------
 Чтобы правильно задать вопрос нужно знать больше половины ответа...
Perl Community 
FREESCO in Ukraine 
PM MAIL   Вверх
arto
Дата 23.3.2007, 13:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1495
Регистрация: 31.10.2004

Репутация: 38
Всего: 40



да, ошибка была.

sub sq {
    my ($a,$b) = (0,0);
    map { defined($_) ? ($a++,$b=0) : ($b++?splice@_,$a,1:$a++); } @_;
    defined($_[0])||splice@_,0,1; defined($_[$#_])||splice@_,$#_,1;
    return @_;
}

(a,undef,undef,undef,undef,undef,undef,b) =>
 (a,undef,b)

(undef,undef,1,2,3,undef,undef,undef,4,undef,5,undef,undef,6,undef,undef) =>
 (1,2,3,undef,4,undef,5,undef,6)

(undef,undef,a,undef,undef,b,undef) =>
 (a,undef,b)

(undef,undef,a) =>
 (a)

(undef,a,undef) =>
 (a)
PM MAIL ICQ   Вверх
tishaishii
Дата 23.3.2007, 16:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Создатель
***


Профиль
Группа: Завсегдатай
Сообщений: 1262
Регистрация: 14.2.2006
Где: Москва

Репутация: 4
Всего: 8



Ни какой map и grep по условиям задачи не годится.
Вот пробуй:
Код
BEGIN {$SPACE="\t\r\n0 "}
sub unsignificantChar {+1==length $_[0] && -1!=index $SPACE, $_[0]}
sub trim {
    my($arr, $i, $count)=shift;
    undef while $i<@$arr && &unsignificantChar($arr->[$i++]);
    splice @$arr, 0, --$i;$i--;
    while($i<@$arr) {
        $count++, next if &unsignificantChar($arr->[$i++]);
    splice @$arr, $i-=$count, $count-1 if $count>1;
    $count=0
    }
    splice @$arr, $i-$count
}
my@arr=qw(0 0 a 0 b 0 0 0 0 0 0 0 c c 0 0 0 0 0 0 0 0 0 c c 0 0 0 0 0 0 c c 0 0 d e 0 0);
&trim(\@arr);
print '['.$_.']' foreach @arr;
print "\n"

PM MAIL ICQ Skype   Вверх
arto
Дата 23.3.2007, 16:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1495
Регистрация: 31.10.2004

Репутация: 38
Всего: 40



почему?

  DB<1> sub sq { my ($a,$b) = (0,0); map { $_ ? ($a++,$b=0) : ($b++?splice@_,$a,1:$a++); } @_; $_[0]||splice@_,0,1; $_[$#_]||splice@_,$#_,1; return @_; }

  DB<2> @arr=qw(0 0 a 0 b 0 0 0 0 0 0 0 c c 0 0 0 0 0 0 0 0 0 c c 0 0 0 0 0 0 c c 0 0 d e 0 0);

  DB<3> print '['.$_.']' foreach sq (@arr);
[a][0][b][0][c][c][0][c][c][0][c][c][0][d][e]
  DB<4>
PM MAIL ICQ   Вверх
Nab
Дата 23.3.2007, 17:12 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 582
Регистрация: 25.3.2006
Где: Kiev

Репутация: 26
Всего: 37



Я вот тут подумал, что с grep еще красивее получиться может:
Код

sub array_compress {
  my $s;
  @_ = grep {($_&&!($s=0))||!$s++} @_;
  $_[0]||shift(@_);
  $_[$#_]||pop(@_);
  return @_
}



--------------------
 Чтобы правильно задать вопрос нужно знать больше половины ответа...
Perl Community 
FREESCO in Ukraine 
PM MAIL   Вверх
arto
Дата 23.3.2007, 19:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1495
Регистрация: 31.10.2004

Репутация: 38
Всего: 40



в данном случае создается второй массив.
PM MAIL ICQ   Вверх
tishaishii
Дата 23.3.2007, 21:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Создатель
***


Профиль
Группа: Завсегдатай
Сообщений: 1262
Регистрация: 14.2.2006
Где: Москва

Репутация: 4
Всего: 8



Цитата
почему?

http://forum.vingrad.ru/index.php?showtopi...t&p=1072959
Цитата
обойтись без временного массива

PM MAIL ICQ Skype   Вверх
arto
Дата 23.3.2007, 23:10 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1495
Регистрация: 31.10.2004

Репутация: 38
Всего: 40



my ($a,$b) = (0,0); map { $_ ? ($a++,$b=0) : ($b++?splice@a,$a,1:$a++); } @a; $_[0]||splice@a,0,1; $_[$#_]||splice@a,$#a,1;  -- где временный массив?

PM MAIL ICQ   Вверх
Nab
Дата 24.3.2007, 00:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 582
Регистрация: 25.3.2006
Где: Kiev

Репутация: 26
Всего: 37



Цитата(arto @  23.3.2007,  19:02 Найти цитируемый пост)
в данном случае создается второй массив.

arto, это ты о чем говорил? об моем варианте или.... ?

А теперь по поводу временных массивов, не думаю что amg, имел ввиду буквально отсутствие временного массива, думаю он больше просил предложить вариант потребляющий меньше ресурсов, как памяти, так и времени....

Цитата(tishaishii @  23.3.2007,  16:15 Найти цитируемый пост)
Ни какой map и grep по условиям задачи не годится.

этими словами он подозреваю имелл ввиду, что манипулирование элементами массива внутри map или grep плохая идея. Если обрабатывать значения массива можно, то изменять размер массива внутри цикла прохода по массиву не есть гуд.... Хорошо у нас тут удаление элементов, и подозреваю перл грамотно отрабатывает эту ситуацию, а если бы было добавление елементов, после текущей позиции или перед ней, что должен делать цикл? вернуться? или не учитывать добавление? а если вы изменяете елемент не текущий, то какой хотели бы обработать, со старым значением или с новым? Вообще это не корректный подход... Даже если он обрабатываеться сейчас по одному алгоритму, я не уверен что такое поведение присутствует во всех версиях перл, и останеться неизменным...

Единственно правильные варианты для splice считаю, while($i < @array) с самостоятельным контролем позиции в массиве. Я это реализовал у себя в первом варианте.

map и grep по большому счету фильтры, которые при этом позволяют обработать по очереди массив имитируя по сути внешний foreach или другой способ организации цикла. Но в большей степени, они могут отфильтровать и вернуть обработанный массив, что очень удобно, я почемуто взялся сразу за map, хотя по идее лучше подходил grep который избавил меня от одного внутреннего условия... Он возвращает елемент в результирующий список только при условии истинности своего выражения, тогда как для map мне пришлось имитировать возврат пустого списка, чтобы елементы не были включены в результирующий набор.

Возможно что и создается второй массив, но он создаеться внутри perl, и думаю вполне оптимально перераспределяется, тогда как использование splice внутри циклов заставляет перл делать еще один внутренний массив, и возможно не один :(... 

А вообще главный тестировщик-оптимизатор у нас amg, вот и попросим его прогнать на достаточно большом и полновесном массиве наши варианты, и по использованию памяти и по времени, пускай выносит результаты в студию...


--------------------
 Чтобы правильно задать вопрос нужно знать больше половины ответа...
Perl Community 
FREESCO in Ukraine 
PM MAIL   Вверх
tishaishii
Дата 24.3.2007, 08:57 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Создатель
***


Профиль
Группа: Завсегдатай
Сообщений: 1262
Регистрация: 14.2.2006
Где: Москва

Репутация: 4
Всего: 8



Цитата
Хорошо у нас тут удаление элементов, и подозреваю перл грамотно отрабатывает эту ситуацию,

Это python более ли менее грамотно работает с оптимизацией памяти, т.к. везде, где можно неявно использует ссылки, а в Perl - проще, там онного нету.
PM MAIL ICQ Skype   Вверх
arto
Дата 25.3.2007, 14:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1495
Регистрация: 31.10.2004

Репутация: 38
Всего: 40



map сейчас оптимизирован, и он не создает массива, если его не просят.
splice тем более.
PM MAIL ICQ   Вверх
Nab
Дата 25.3.2007, 15:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 582
Регистрация: 25.3.2006
Где: Kiev

Репутация: 26
Всего: 37



Цитата(arto @  25.3.2007,  14:24 Найти цитируемый пост)
map сейчас оптимизирован, и он не создает массива, если его не просят.splice тем более.

Возможно, а при вызове slice из map? я к примеру не уверен, скорее даже наоборот....


--------------------
 Чтобы правильно задать вопрос нужно знать больше половины ответа...
Perl Community 
FREESCO in Ukraine 
PM MAIL   Вверх
arto
Дата 25.3.2007, 16:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1495
Регистрация: 31.10.2004

Репутация: 38
Всего: 40



splice манипулитует оригинальным массивом.
грубо говоря проверяем элемент массива по указателю.
PM MAIL ICQ   Вверх
tishaishii
Дата 25.3.2007, 20:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Создатель
***


Профиль
Группа: Завсегдатай
Сообщений: 1262
Регистрация: 14.2.2006
Где: Москва

Репутация: 4
Всего: 8



Это вы про какую версию говорите?
PM MAIL ICQ Skype   Вверх
amg
  Дата 26.3.2007, 09:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1145
Регистрация: 3.8.2006
Где: Новосибирск

Репутация: 38
Всего: 50



Ну вот, потестировал. Тестируемый код приводить не буду, чтобы не занимать места. (arto-ref - это код arto с передачей массива по ссылке и модификацией его "по месту"). В колонке "Память" со знаком минус - это кол-во памяти, потребляеемой скриптом на создание массива. 
Код

Плотный массив        Время Память
----------------------------------
me1                   1.826 202-58
Nab-map               2.528 190-58
Nab-grep              2.979 190-58
tishaishii            2.551  64-58
arto                  2.213 198-58
arto-ref              0.703  89-58

Разреженный массив    Время Память
----------------------------------
me1                   0.162  24-14
Nab-map               0.286  24-14
Nab-grep              0.206  23-14
tishaishii            0.961  18-14
arto                  8.430  27-14
arto-ref              8.490  26-14

Nab-grep - это перл (в обоих смыслах). В коде tishaishii придется хорошо поразбираться, есть ради чего - дополнительная память почти не используется. Код arto удивительно быстро работает на "плотных" массивах - тоже надо поразбираться.

Господа! Всем большое спасибо.
PM MAIL   Вверх
Nab
Дата 26.3.2007, 12:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 582
Регистрация: 25.3.2006
Где: Kiev

Репутация: 26
Всего: 37



Ой, действительно интересные результаты smile
А почему мой первый вариант не включили, по моему он также будет наименее прожорлив, да и не вызывает slice для каждого елемента, то есть может дать выиграш на разреженном массиве...
Код

sub compress_array {
    my ($i, $space) = (0,0);
    # пока не достигли конца массива
    while ($i < @_) {
        # если елемент не пустой
        if ($_[$i++]) {
         # если предыдущие были пустыми елементами, то мы их удаляем
            if ($space--) {
                # откатываем индекс
                $i -= $space;
                # удаляем пустые елементы
                splice @_, $i - 1, $space;
            }
            # обнуляем счетчик пустых елементов
            $space = 0
        } else {
            # здесь мы будем если у нас пустой елемент,
            # мы его пропускаем, но увеличиваем счетчик...
            # чтоб обработать впоследствии
         $space++;
        }
    }
    # а здесь мы удаляем если в конце массива у нас пустые есть, мы то уже из цикла вышли по окончании индекса
    splice @_, $i - $space, $space if $space;
    # по необходимости удаляем первый
    splice @_, 0, 1 unless $_[0];
    return @_
}

Я его немного переделал, вполне удовлетворяет условиям задачи...

Добавлено через 13 минут и 48 секунд
А вот все мои варианты с передачей по ссылке, надеюсь будут менее прожорливы :(
Код

sub compress_array_grep {
    my $array = shift;
    my $s;
    @$array = grep {($_&&!($s=0))||!$s++} @$array;
    $array->[0]||shift(@$array);
    $array->[$#$array]||pop(@$array);
}

sub compress_array_map {
    my $array = shift;
    my $s;
    @$array = map {$_?($s=0 or$_):$s++?():$_} @$array;
    $array->[0]||shift(@$array);
    $array->[$#$array]||pop(@$array);
}


sub compress_array {
    my $array = shift;
    my ($i, $space) = (0,0);
    while ($i < @$array) {
        if ($array->[$i++]) {
            if ($space--) {
                $i -= $space;
                splice @$array, $i - 1, $space;
            }
            $space = 0
        } else {
         $space++;
        }
    }
    splice @$array, $i - $space, $space if $space;
    splice @$array, 0, 1 unless $array->[0];
}


Это сообщение отредактировал(а) Nab - 26.3.2007, 12:30


--------------------
 Чтобы правильно задать вопрос нужно знать больше половины ответа...
Perl Community 
FREESCO in Ukraine 
PM MAIL   Вверх
Nab
Дата 26.3.2007, 12:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 582
Регистрация: 25.3.2006
Где: Kiev

Репутация: 26
Всего: 37



Кстати amg, свой вариант опубликуй...


--------------------
 Чтобы правильно задать вопрос нужно знать больше половины ответа...
Perl Community 
FREESCO in Ukraine 
PM MAIL   Вверх
amg
Дата 26.3.2007, 16:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1145
Регистрация: 3.8.2006
Где: Новосибирск

Репутация: 38
Всего: 50



Цитата(Nab @  26.3.2007,  12:44 Найти цитируемый пост)
Кстати amg, свой вариант опубликуй...

Код

sub me1 {
  my $s = join ':', @_;
  $s =~ s/:0(:0)+/:0/g;
  return split ':', $s;
}
Я там где-то раньше говорил, что этот код медленно работает на реальных массивах, но это не так. Работает быстро, но память жрет...

Добавлено через 5 минут и 35 секунд
Цитата(Nab @  26.3.2007,  12:27 Найти цитируемый пост)
А почему мой первый вариант не включили
Да что-то он у меня сразу не пошел, а думать, в чем дело, было, как всегда, лень. Nab, завтра обязательно проверю твои новые варианты.


Это сообщение отредактировал(а) amg - 26.3.2007, 16:10
PM MAIL   Вверх
tishaishii
Дата 26.3.2007, 19:52 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Создатель
***


Профиль
Группа: Завсегдатай
Сообщений: 1262
Регистрация: 14.2.2006
Где: Москва

Репутация: 4
Всего: 8



Ну большие массивы много и памяти будут кушать.
Значит, надо этот массив хранить на диске и обрабатывать поэлементно.
Код
use IO::Handle;

sub separator {
    my($result, $len, @letters)=(undef, shift, 'a'..'z', 'A'..'Z', '0'..'9');
    $result.=$letters[@letters*rand] while $len--;
    +'='.$result.'='
}

my$seplen=0x10;
my$tin=($ENV{TEMP}||$ENV{TMP})."\\".time;
my$tout=$tin.'.out';

my@arr=(<<'.', <<'.', <<'.', <<'.', <<'.', <<'.', <<'.', <<'.', <<'.', <<'.');
lkdsklfsd
sdfl;dsl;f
dsflds'fdsfds\
.
sdfdsf        sdfdsf
.
.
sadsad
sadsad
.
.
sadsad

.
sdflslf
.
sdfsdl;fl;sdf
dsf;ds
.
,    
.
0
.

my$separator=&separator($seplen);

#пиши массив в файлик
open my$fh, '>'.$tin;binmode $fh;
$fh->print(shift(@arr), $separator) while @arr;
close $fh;

$/=$separator;
$seplen+=2;

#потом этот файлик обрабатывай
open my$out, '>'.$tout;binmode $out;
open my$in, '<'.$tin;binmode $in;
while(<$in>) {
    substr $_, -$seplen, $seplen, undef;
    $out->print('['.$_.']') if length && !/^[\t\r\n0 ]+$/o;
}
close $in;
close $out;

print $tin, "\n", $tout, "\n";


Добавлено через 2 минуты и 43 секунды
Ну большие массивы много и памяти будут кушать.
Значит, надо этот массив хранить на диске и обрабатывать поэлементно.
Код
use IO::Handle;

sub separator {
    my($result, $len, @letters)=(undef, shift, 'a'..'z', 'A'..'Z', '0'..'9');
    $result.=$letters[@letters*rand] while $len--;
    +'='.$result.'='
}

my$seplen=0x10;
my$tin=($ENV{TEMP}||$ENV{TMP})."\\".time;
my$tout=$tin.'.out';

my@arr=(<<'.', <<'.', <<'.', <<'.', <<'.', <<'.', <<'.', <<'.', <<'.', <<'.');
lkdsklfsd
sdfl;dsl;f
dsflds'fdsfds\
.
sdfdsf        sdfdsf
.
.
sadsad
sadsad
.
.
sadsad

.
sdflslf
.
sdfsdl;fl;sdf
dsf;ds
.
,    
.
0
.

my$separator=&separator($seplen);

#пиши массив в файлик
open my$fh, '>'.$tin;binmode $fh;
$fh->print(shift(@arr), $separator) while @arr;
close $fh;

$/=$separator;
$seplen+=2;

#потом этот файлик обрабатывай
open my$out, '>'.$tout;binmode $out;
open my$in, '<'.$tin;binmode $in;
while(<$in>) {
    substr $_, -$seplen, $seplen, undef;
    $out->print('['.$_.']') if length && !/^[\t\r\n0 ]+$/o;
}
close $in;
close $out;

print $tin, "\n", $tout, "\n";


Добавлено через 2 минуты и 54 секунды
Ну большие массивы много и памяти будут кушать.
Значит, надо этот массив хранить на диске и обрабатывать поэлементно.
Код
use IO::Handle;

sub separator {
    my($result, $len, @letters)=(undef, shift, 'a'..'z', 'A'..'Z', '0'..'9');
    $result.=$letters[@letters*rand] while $len--;
    +'='.$result.'='
}

my$seplen=0x10;
my$tin=($ENV{TEMP}||$ENV{TMP})."\\".time;
my$tout=$tin.'.out';

my@arr=(<<'.', <<'.', <<'.', <<'.', <<'.', <<'.', <<'.', <<'.', <<'.', <<'.');
lkdsklfsd
sdfl;dsl;f
dsflds'fdsfds\
.
sdfdsf        sdfdsf
.
.
sadsad
sadsad
.
.
sadsad

.
sdflslf
.
sdfsdl;fl;sdf
dsf;ds
.
,    
.
0
.

my$separator=&separator($seplen);

#пиши массив в файлик
open my$fh, '>'.$tin;binmode $fh;
$fh->print(shift(@arr), $separator) while @arr;
close $fh;

$/=$separator;
$seplen+=2;

#потом этот файлик обрабатывай
open my$out, '>'.$tout;binmode $out;
open my$in, '<'.$tin;binmode $in;
while(<$in>) {
    substr $_, -$seplen, $seplen, undef;
    $out->print('['.$_.']') if length && !/^[\t\r\n0 ]+$/o;
}
close $in;
close $out;

print $tin, "\n", $tout, "\n";

PM MAIL ICQ Skype   Вверх
amg
Дата 27.3.2007, 08:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1145
Регистрация: 3.8.2006
Где: Новосибирск

Репутация: 38
Всего: 50



Nab, потестировал твой новый код. По потреблению памяти все осталось по-прежнему, зато заметно увеличилась скорость. Теперь compress_array_grep - абсолютный чемпион smile . compress_array не использует дополнительную память, но у него есть такая неприятная особенность - с увеличением размера массива (каждый следующий набор данных в таблице соответствуют удвоенному массиву) резко растет время (кстати, ровно такая же ситуация с кодом tishaishii)
Код

Разреженный массив    Время Память  Время Память  Время Память  Время Память
-----------------------------------------------------------------------------
me1                   0.089 13-1    0.167 24-14   0.702 91-63   1.932 179-123
compress_array        0.198 11-1    0.532 18-14   9.044 63-63  36.59  123-123
compress_array_map    0.135 13-1    0.269 21-14   1.087 80-63   2.132 157-123
compress_array_grep   0.080 12-1    0.164 20-14   0.658 75-63   1.296 147-123

 
PM MAIL   Вверх
tishaishii
Дата 27.3.2007, 10:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Создатель
***


Профиль
Группа: Завсегдатай
Сообщений: 1262
Регистрация: 14.2.2006
Где: Москва

Репутация: 4
Всего: 8



Прошу прощения, проблемы со связью.
Цитата
кстати, ровно такая же ситуация с кодом tishaishii

Ну если ты не будешь хранить весь массив в оперативке, как у меня в примере для лучшего понимания, а когда-то запишешь однажды в файл с  разделителями, то память меняться почти не должна. Смысл-то цикл делать для записи в файл, в котором нет проверки на пустоту, а потом открывать этот файл, разбирать и заново его фильтровать. Вобщем, если будешь только читать из файла с разделителями, то будешь без напрягов работать с большими массивами, независимо от оперативки и подкачки.  Откуда ей рости во время чтения.

Это сообщение отредактировал(а) tishaishii - 27.3.2007, 10:42
PM MAIL ICQ Skype   Вверх
G0rinich
Дата 4.4.2007, 15:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 35
Регистрация: 21.8.2006

Репутация: нет
Всего: 1



Просто красивый код )))
Код

#!/usr/bin/perl

sub clean_arr{
push@_=>undef;
defined$_[0]||
defined$_[-1]?
push@_=>shift:
shift for 1 ..
@_; pop; (@_)}

@a = clean_arr
( undef,undef,
1,2,3,undef,4,
undef,5,undef,
undef,undef,6,
undef,undef );

print join'-',
@a;


Взято тут

Это сообщение отредактировал(а) G0rinich - 4.4.2007, 15:55
PM MAIL   Вверх
Страницы: (3) [Все] 1 2 3 
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Perl"
korob2001
sharq
  • В этом разделе обсуждаются общие вопросы по языку Perl
  • Если ваш вопрос относится к системному программированию, задавайте его здесь
  • Если ваш вопрос относится к CGI программированию, задавайте его здесь
  • Интерпретатор Perl можно скачать здесь ActiveState, O'REILLY, The source for Perl
  • Справочное руководство "Установка perl-модулей", можно скачать здесь


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, korob2001, sharq.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Perl: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.1263 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.