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


Автор: AlexanderI 20.7.2006, 10:34
Помогите создать условие.

У меня есть массив:
@massiv = qw(4 10 16 20);
Каким образом создать условие так, чтобы проверялось сразу принадлежность каждого значения массива ?

т.е например:

Код

if ($cifra равно (4 или 10 или 16 или 20) ){
# чёт выполняется
}
  

Автор: Nab 20.7.2006, 15:23
неее, пользуйся лучше хешем... 

или вот так  smile 
Код

@massiv = qw(4 10 16 20);
@{%mass}{@massiv} =1 x @massiv;
print 'OK' if exists $mass{$cifra};
 

Тут вкралась ошибочка, смотрите топик ниже

Правильно вот так:
Код

@massiv = qw(4 10 16 20);
@{%mass}{@massiv} = (1) x @massiv;
print 'OK' if exists $mass{$cifra};
 
Хотя в данном конкретном случае это никак не влияет, мы проверяем существование ключа а не его истиннось, но ради принципа всеже этот вариант вернее...

Автор: Throne 20.7.2006, 15:44
В крайнем случае можно изобразить что-то типа
Код

if ($cifra eq 4 || $cifra eq 6 || $cifra eq 8) {
print "$cifra\n";
};
  

Автор: DiverD 20.7.2006, 19:47
еще как вариант с форейчем:
Код


@massiv = qw(4 10 16 20);
foreach(@massiv) 
{
    $_ == 1 ? print "[ok]\n" : print "[no]\n";
}

Автор: Ramirez 21.7.2006, 10:18
вот еще вариантец

Код

print '[ok]' if defined $massiv[$cifra]
  

Автор: lanD 21.7.2006, 10:29
Почитай про логические операторы 

Автор: igorold 21.7.2006, 12:25
Цитата(Ramirez @  21.7.2006,  10:18 Найти цитируемый пост)
if defined $massiv[$cifra]

это из другой оперы - это ты проверяешь определен ли энный элемент массива, где эн=$cifra
 

Автор: sharq 21.7.2006, 14:42
AlexanderI, 

Код

if (grep {$cifra == $_} @massiv) { # здесь grep используется в скалярном контексте
  ...
}


 smile 
 

Автор: Nab 21.7.2006, 14:57
Код

print "OK" if map {/$cifra/} @massiv; # Играем в ПерлГольф? 

;)
 

Автор: sharq 28.7.2006, 22:19
Nab, т.е. в твоем варианте прокатит:

$cifra = 4, а какой-нить элемент массива @massiv 345 или 4me smile 

 smile  

Автор: Nab 28.7.2006, 23:34
Ну вот началось  smile 
я так и знал что начнеться smile 
блин и в праздник обижают  smile 

все знают как помочь беде  smile 

ну ладно, так и быть скажу  smile  ....


Код

print "Воооо!!! нашли !!!" if map {/^\Q$cifra\E$/} @massiv; 

или
Код

print "Ooops!! found again :)" if map { $cifra == $_ } @massiv; 
 

Автор: Danissimo 14.8.2006, 17:14
Цитата(Nab @ 20.7.2006,  15:23)
Код

@massiv = qw(4 10 16 20);
@{%mass}{@massiv} =1 x @massiv;
print 'OK' if exists $mass{$cifra};

2 Nab:
Переведи, плз, 2-ю строчку

Автор: Nab 15.8.2006, 20:34
Цитата(Danissimo @ 14.8.2006,  17:14)
Цитата(Nab @ 20.7.2006,  15:23)
Код

@massiv = qw(4 10 16 20);
@{%mass}{@massiv} =1 x @massiv;
print 'OK' if exists $mass{$cifra};

2 Nab:
Переведи, плз, 2-ю строчку

Ууу, ее сложно в двух словах объяснить, но я попытаюсь smile

В левой части выражения мы формируем срез хеша предсталенный в виде массива. И каждому элементу которого в правой части присваиваем 1.

Срез хеша это приблизительно вот так:

Код

#есть 
my %mass = ()

#чтобы добыть сразу несколько значений, делаем так
@mass = ($mass{'one'}, $mass{'two'}, $mass{'three'});

#чтобы не писать каждое значение отдельно сразу представим их как массив
@mass = @{%mass}{'one','two','three'};

#то есть, хеш берем как массив значений, по списку ключей
#ну а так как у нас есть список 
@massiv = ('one','two','three');
#то пишем еще короче
@mass = @{%mass}{@massiv};


Так как нас интересует присваивание то этот срез хеша попадает в левую часть. В правую попадает вот такое выражение:
Код

(1) x @massiv;



оператор x - это повторитель, он повторяет элемент (число, строку) указанный как левый операнд... правый операнд определяет количество этих самых элементов.
В нашем случае, это массив, который в  скалярном контексте  возвращает количество своих элементов.

Вообще это один из самых простых способов заполнить хеш или массив повторяющимся или дефолтным значением.

Я не скажу что это очень сложно, но осваивается с трудом smile.

Этот способ хорошо применим когда нужно перевернуть хеш, то есть поменять местами ключи и значения...

Код

@{%mass}{values %mass} = keys %mass;


Конечно при одинаковых значениях элемент может потеряться, но какой именно, эт боюсь не скажу smile и за этим вам самим прийдется следить  smile 

Ну вот вроде и все, надеюсь понятно объяснил  smile 
Если что спрашивайте...

Автор: Danissimo 16.8.2006, 12:06
Супер!!!

1. Правильно я понимаю, что
Код

@{%hash}{@mass} = ...;
# это то же самое, что и
(%hash{@mass}) = ...


2. Про 1 x @mass я так и думал. Тока не понятно, зачем? Почему просто не сказать @{%hash}{@mass} = 1;?

3. Где написано, что в конструкции @{%hash}{@mass} сначала выполняется %hash{@mass}, а затем уже результат преобразовывается к массиву (или списку)?

4. Наскока я мог понять из прочтенного, список и массив -- разные вещи. (1, 2, 3) -- список, @x = (1, 2, 3) -- массив, в который скопированы элементы списка. Это верно?

5. Меня удручает, что не могу найти четких правил о семантике языка. Например, где однозначно говорится, в чем отличия в интерпретации @%hash{@mass} и @{%hash}{@mass}. Где?

Если не сложно, конечно =)

Автор: Nab 16.8.2006, 12:48
Так, сразу приношу извинения кого ввел в заблуждение:

Конструкция '1 x 10' создаст строку из десяти единичек. В нашем же случае нужны отдельные элементы, посему их нужно екранировать...  
Вот верный код:
Код

(1) x 10;



Цитата(Danissimo @  16.8.2006,  12:06 Найти цитируемый пост)
1. Правильно я понимаю, что
Код

@{%hash}{@mass} = ...;    
# это то же самое, что и    
(%hash{@mass}) = ...

Нет не правильно, давай ты хотя бы сначала попробуешь запустить, то что пишеш а потом спрашивать про аналогичность....


Цитата(Danissimo @  16.8.2006,  12:06 Найти цитируемый пост)
2. Про 1 x @mass я так и думал. Тока не понятно, зачем? Почему просто не сказать @{%hash}{@mass} = 1;?

Аналогично предыдущему... Сначала самому проверить, а потом писать. С учетом того что я тоже ошибся smile


Цитата(Danissimo @  16.8.2006,  12:06 Найти цитируемый пост)
3. Где написано, что в конструкции @{%hash}{@mass} сначала выполняется %hash{@mass}, а затем уже результат преобразовывается к массиву (или списку)?

С чего ты это взял? Эта конструкция вообще не верна.


Цитата(Danissimo @  16.8.2006,  12:06 Найти цитируемый пост)
4. Наскока я мог понять из прочтенного, список и массив -- разные вещи. (1, 2, 3) -- список, @x = (1, 2, 3) -- массив, в который скопированы элементы списка. Это верно?

Нет  smile  Список и массив одно и тоже...


Цитата(Danissimo @  16.8.2006,  12:06 Найти цитируемый пост)
5. Меня удручает, что не могу найти четких правил о семантике языка. Например, где однозначно говорится, в чем отличия в интерпретации @%hash{@mass} и @{%hash}{@mass}. Где?

Аналогично первому, сначала проверить на жизнеспособность а потом писать...

Семантика перла многовариантна, это фича  smile языка, что любое действие можно сделать более чем одним способом smile

Купи LamaBook И очень рекомендую Perl CookBook... Как раз в ней это все есть....

Автор: Ramirez 9.9.2006, 00:15
Замечательно. По-моему, посты товарища Nab'a вполне достойны размещения в каком нить FAQ.
Вот кстати, иногода бывает такая ситуация:
Код

@arr = qw(4 10 16 20);
$hash{$_} = $_ foreach @arr;


т.е. из списка надо сделать хеш где значение ключа равно его(ключа) имени.
мне кажется должен быть более красивый вариант, без foreach...

Автор: Nab 9.9.2006, 01:00
Цитата(Ramirez @  9.9.2006,  00:15 Найти цитируемый пост)
Замечательно. По-моему, посты товарища Nab'a вполне достойны размещения в каком нить FAQ.

Спасибо конечно smile

А по существу, то,  наверно вот так :
Код

@arr = qw(4 10 16 20);    
@{%hash}{@arr} = @arr;

Автор: korob2001 10.9.2006, 04:08
Ещё, как вариант:
Код

my $number = 16;
my @array = qw(4 10 16 20);

print "Exists" if "@array" =~ /\b$number\b/;

Автор: sharq 11.9.2006, 09:49
korob2001, отличный вариант! Супер!  smile 


Автор: amg 12.9.2006, 08:30
Нравится мне этот форум! Есть над чем подумать.
Вот, например, здесь предложили несколько вариантов решения практически важной задачи: выяснить, присутствует ли в списке данный элемент. Мне часто приходится иметь дело с огромными списками, поэтому я эти варианты поисследовал на предмет эффективности. Привожу результаты, может, кому-нибудь еще будет интересно.
Код

$cifra = 30; @massiv = ('4', '10', '16', '20') x 1e6;

# Nab
@{%mass}{@massiv} = (1) x @massiv; print "OK\n" if exists $mass{$cifra};

# diverd
foreach (@massiv) {print "OK\n" if $_==$cifra}

# sharq
print "OK\n" if (grep {$cifra == $_} @massiv);

# Nab1
print "OK\n" if map {/^\Q$cifra\E$/} @massiv;

# korob2001
print "OK\n" if "@massiv" =~ /\b$cifra\b/;

# List::Util
use List::Util qw(first); print "OK\n" if first { $cifra == $_ } @massiv;

Результаты:
Код

          Время,с Память,Mb
Nab         1.39  124
diverd      1.88   61
sharq       0.79   61
Nab1        3.50    0
korob2001   0.69   21
List::Util  0.65   61

Я для себя запомню два варианта: "korob2001" - совершенно неожиданный, но очень эффективный, и "Nab1" - не быстрый, но зато не требующий дополнительной памяти.

Автор: Nab 12.9.2006, 08:54
amg, ты манияк от перла smile  Оптимизатор блин smile

Кстати мне не понятны результаты вариантов diverd и sharq, они по идее аналогичны моему, но отжирают памяти порядочно smile. 

Конечно они быстрее, но ...  Видно какое-то оптимизирующее кеширование применяется... И похоже что одинаковое.

Автор: Nab 12.9.2006, 09:37
Кстати в моем первом варианте, вопрос не до конца продуман

Код

$cifra = 30; @massiv = ('4', '10', '16', '20') x 1e6;    

@{%mass}{@massiv} = (1) x @massiv; print "OK\n" if exists $mass{$cifra};


Ведь в реальности получается что все время потрачено на заполнение и конвертирование одной формы списка в другую, хеш. Хотя у большинства это было просто заполнение массива. Я бы наверно предпочел сразу формировать хеш а не первоначальный список, но идея даже не в этом... smile
Так как в список уникальных значений всего 4 то хеш в конечном итоге получиться всего из 4 элементов, и поиск по нему будет мизерно быстр smile тут нужно или заполнять список уникальными значениями, типа i++ или сразу из них же формировать хеш, думаю результат будет другим smile. попробуешь? для чистоты эксперимента?

Вариант 1
Код

$cifra = 1e6 + 1; while ($i < 1e6) {$massiv[$i++] = 1};    

@{%mass}{@massiv} = (1) x @massiv; print "OK\n" if exists $mass{$cifra};


Вариант 2
Код

$cifra = 1e6 + 1; while ($i < 1e6) {$massiv[$i++] = 1};    

print "OK\n" if exists $mass{$cifra};


можно пргнать с уникальным списком все варианты smile

Автор: amg 12.9.2006, 12:18
Ага, когда компутер сначала надолго замолкает, а потом начинает молотить диском, впадая в глухой своп, поневоле станешь оптимизатором.

Мне вот тоже непонятно, почему вариант "Nab1" не требует памяти, хотя, на первый взгляд, должен, а "diverd" - требует, хотя, казалось бы, и незачем. В общем, много еще нужно учиться.

ЗЫ Это я на предыдущий пост...

Автор: amg 12.9.2006, 13:43
Цитата(Nab @  12.9.2006,  09:37 Найти цитируемый пост)
... Ведь в реальности получается что все время потрачено на заполнение ...
 Нет, время на заполнение первоначального массива не учитывалось.
Цитата
Так как в список уникальных значений всего 4 то хеш в конечном итоге получиться всего из 4 элементов, и поиск по нему будет мизерно быстр
 Дополнительное время (см. ниже) тратится, видимо, на формирование хэша с более, чем 4 элементами. А поиск по хэшу я уже http://forum.vingrad.ru/index.php?showtopic=106011&view=findpost&p=813652, он пренебрежимо быстр и для очень больших хэшей (удивительно, однако). 
Цитата
тут нужно или заполнять список уникальными значениями, типа i++ . попробуешь? для чистоты эксперимента?
С удовольствием! 
Код

$cifra = 4e6 + 1; while ($i < 4e6) {$massiv[$i++] = 1};
Код

          Время,с
Nab         2.68
diverd      1.09
sharq       0.78
Nab1        3.31
korob2001   0.65
List::Util  0.63
 Фактически, изменились первые две строчки, в 1-й замедление (можно понять, почему), во 2-й - ускорение (непонятно почему)

Автор: sharq 12.9.2006, 13:58
amg, интересно с помощью чего ты время тестировал? 
Попробуй Benchmark и повторов этак 10_000, привиди код и результаты.
А с помощью Memchmark замереть память - не совсем хорошо, т.к.
Цитата

BUGS ^

This is a very early release, alpha software, expect bugs on it.

The API is not stable. I will change it when required for improvement.


А на счет вариантов мое мнение - вариант korob2001 - красивый, быстро работает из-за регулярных выражений, но есть недостатки, н-р - не найдешь индекс, найденного эелемента.
Мой вариант - это стандартный  в данной ситуации, в стиле Perl, но также есть недостатки.
Вариант Nab (последний) - это вариант языка Си, прелести Perl нет. А первый вариант - map для этого не используется.
List::Util - хороший модуль, но он загружается в память и для небольшой задачи это не нужно!
Обычным перебором - хорошо, но не красиво  smile 

Итог - вариант стоит использовать тот, кот. в данный ситуации будет наиболее приемлем.
Н-р, я использую всегда красивый вариант, если не требуется оптимального решения! Поэтому grep и regexp - это то, что надо.

 smile 

Автор: Nab 12.9.2006, 17:42
Все верно ребята вы говорите smile 

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

Ну и конечно о красоте smile Прелесть перла, что это можно сделать не одним способом smile  А красота у всех разная ... 
Хотя мои решения с map не такое уж страшное, и как оказалось и в нем есть рациональное зерно smile

PS: amg, а покаж ка, как ты мерял?

Автор: Danissimo 12.9.2006, 17:49
amg, хочу сказать, не удивляйся, что время поиска по хеш-таблице не зависит от количества элементов. Если посмотреть на цели, с которыми разрабатывались хеш-таблицы, то именно эта цель и преследовалась, а именно: время поиска не должно зависеть от количества элементов, то есть должно быть константным. На языке алгоритмического анализа это записывается так: O(n) = const =)) Я не знаю никакой другой структуры данных, у которой алгоритмическая сложность была бы величиной постоянной. Так что все работает, как и должно =)

Автор: korob2001 13.9.2006, 03:51
Кстати, amg если будет желаение, можешь попробовать компилировать шаблон только один раз, т.е. добавить модификатор "о" к регулярному выражению. Ведь у нас всё равно не меняется значение переменной $number.
Код

print "Exists" if "@array" =~ /\b$number\b/o;

Автор: amg 13.9.2006, 12:02
Цитата(sharq @  12.9.2006,  13:58 Найти цитируемый пост)
amg, интересно с помощью чего ты время тестировал? Попробуй Benchmark и повторов этак 10_000, привиди код и результаты.
Использовал два способа. 1. Тупое замерение времени до и после куска кода:
Код

use Time::HiRes qw( time );

$cifra = 30; @massiv = ('4', '10', '16', '20') x 1e6;

$time0 = time();
@{%mass}{@massiv} = (1) x @massiv; print "OK\n" if exists $mass{$cifra};
$time1 = time(); print "Nab: \t", $time1 - $time0, "\n";

$time0 = time();
foreach (@massiv) {print "OK\n" if $_==$cifra}
$time1 = time(); print "diverd: \t", $time1 - $time0, "\n";

$time0 = time();
print "OK\n" if (grep {$cifra == $_} @massiv);
$time1 = time(); print "sharq: \t", $time1 - $time0, "\n";

$time0 = time();
print "OK\n" if map {/^\Q$cifra\E$/} @massiv;
$time1 = time(); print "Nab1: \t", $time1 - $time0, "\n";

$time0 = time();
print "OK\n" if "@massiv" =~ /\b$cifra\b/;
$time1 = time(); print "korob2001: \t", $time1 - $time0, "\n";

$time0 = time();
use List::Util qw(first); print "OK\n" if first {$cifra == $_} @massiv;
$time1 = time(); print "List::Util: \t", $time1 - $time0, "\n";
 2. Benchmark
Код

use Benchmark qw(:all);

$cifra = 30; @massiv = ('4', '10', '16', '20') x 1e6;

timethese(-10,{
Nab => sub {
@{%mass}{@massiv} = (1) x @massiv; print "OK\n" if exists $mass{$cifra};
},

diverd => sub {
foreach (@massiv) {print "OK\n" if $_==$cifra}
},

sharq => sub {
print "OK\n" if (grep {$cifra == $_} @massiv);
},

Nab1 => sub {
print "OK\n" if map {/^\Q$cifra\E$/} @massiv;
},

korob2001 => sub {
print "OK\n" if "@massiv" =~ /\b$cifra\b/;
},

'List::Util' => sub {
use List::Util qw(first); print "OK\n" if first { $cifra == $_ } @massiv;
},
});
 
Результаты (больше проценты - быстрее).
Код

          Прямое измерение времени       Benchmark            Benchmark
            массив 4e6 элементов    массив 4e6 элементов  массив 4 элемента
Nab                 256%                    218%                 88%
diverd              192%                    245%                 86%
sharq               436%                    390%                219%
Nab1                100%                    100%                100%
korob2001           503%                    543%                127%
List::Util          542%                    506%                144%
 На большом массиве результаты обоих способов похожи (естественно). Любопытно, что на маленьком массиве все совсем по-другому. Быстрее всех становится вариант "sharq". Этот вариант хорош еще и тем, что он самый "читабельный" (для меня).

Цитата
А с помощью Memchmark замереть память - не совсем хорошо...
Ничего лучше я, к сожалению, не нашел. Другой способ, мне известный, - запускаю top с интервалом обновления 0.2 с и пристально вглядываюсь в быстро мелькающие цифры - весьма неудобен и утомителен.


Автор: amg 13.9.2006, 12:19
Цитата(Nab @  12.9.2006,  17:42 Найти цитируемый пост)
... если мне нужно проверять наличие значения как такового, изначально использовал бы хеш ... 
Совершенно согласен, это самое правильное, если заранее знаешь, что будешь проводить поиск.
Цитата
Хотя мои решения с map не такое уж страшное, и как оказалось и в нем есть рациональное зерно
 Еще какое! То, что Ваш вариант с map не использует дополнительную память, может оказаться критическим преимуществом. Почему не использует - буду еще разбираться.
Цитата
PS: amg, а покаж ка, как ты мерял?
Это - уже, см. выше.

Добавлено @ 12:21 
Цитата(Danissimo @  12.9.2006,  17:49 Найти цитируемый пост)
amg, хочу сказать, не удивляйся, что время поиска по хеш-таблице не зависит от количества элементов. Если посмотреть на цели, с которыми разрабатывались хеш-таблицы, то именно эта цель и преследовалась, а именно: время поиска не должно зависеть от количества элементов, то есть должно быть константным. На языке алгоритмического анализа это записывается так: O(n) = const =)) Я не знаю никакой другой структуры данных, у которой алгоритмическая сложность была бы величиной постоянной. Так что все работает, как и должно =)

Спасибо! Буду знать.

Добавлено @ 12:28 
Цитата(korob2001 @  13.9.2006,  03:51 Найти цитируемый пост)
Кстати, amg если будет желаение, можешь попробовать компилировать шаблон только один раз, т.е. добавить модификатор "о" к регулярному выражению.
Спасибо! Попробовал. Есть ускорение, особенно при многократном поиске внутри небольших массивов.

P.S. Прошу у всех прощения за многословие.

Автор: korob2001 14.9.2006, 00:12
Цитата(amg @  13.9.2006,  09:19 Найти цитируемый пост)
P.S. Прошу у всех прощения за многословие.

Многословие в тему, потому прощения просить не нужно.  smile 

Автор: evilsoul 9.11.2008, 19:54
Цитата

Нет  Список и массив одно и тоже...

А ты попробуй к списку и массиву обратиться в скалярном контексте, и увидишь разницу

Автор: kavkaz 10.11.2008, 13:58
думаю за два года он уже это сам понял smile

Автор: evilsoul 10.11.2008, 21:16
Да а я чо то на даты и не глядел smile, просто лазил читал решил свое слово вставить smile

Автор: Nab 15.2.2010, 21:05
Цитата(evilsoul @  9.11.2008,  19:54 Найти цитируемый пост)
Цитата(Nab)
Нет  Список и массив одно и тоже...

А ты попробуй к списку и массиву обратиться в скалярном контексте, и увидишь разницу

И какова она?
Цитата(kavkaz)

думаю за два года он уже это сам понял smile

Время не столь важно...

Автор: krypt3r 16.2.2010, 11:15
Археологи)

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