Чи існує обмеження у Perlo's Glob?


9

Я виконую наступні очікування повернення рядків з 5 символів:

while (glob '{a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z}'x5) {
  print "$_\n";
}

але він повертає лише 4 символи:

anbc
anbd
anbe
anbf
anbg
...

Однак, коли я скорочую кількість символів у списку:

while (glob '{a,b,c,d,e,f,g,h,i,j,k,l,m}'x5) {
  print "$_\n";
}

він повертається правильно:

aamid
aamie
aamif
aamig
aamih
...

Може хтось скажіть, будь ласка, чого я тут пропускаю, чи є якась межа? чи є шлях до цього?

Якщо це має якусь різницю, він повертає однаковий результат і в perl 5.26іperl 5.28


Раніше: stackoverflow.com/a/58852104 stackoverflow.com/a/58853045 Використовуйте модуль, що забезпечує ітератор, а не зловживає функцією глобуса. p3rl.org/Algorithm::Combinatorics p3rl.org/Algorithm::Loops
daxim

Дякую @daxim. Проблема в тому, що я зараз намагаюся завантажувати модулі будь-якого типу, у мене проблема з cpan, яка скаржиться на Win32 :: Console, але ppm недоступна в perl 5.28, тому я можу завантажити модуль для cpan, щоб перестати скаржитися.
Джеррі

Спасибі @zdim ціную весь час та зусилля.
Джеррі

Я щойно зрозумів ... Ви хочете взагалі цей перетасований (рандомізований) чи просто повний список?
здим

@zdim просто повний список. :)
Джеррі

Відповіді:


6

Все має якесь обмеження.

Ось чистий модуль Perl, який може зробити це для вас повторно. Він не генерує весь список відразу, і ви починаєте отримувати результати негайно:

use v5.10;

use Set::CrossProduct;

my $set = Set::CrossProduct->new( [ ([ 'a'..'z' ]) x 5 ] );

while( my $item = $set->get ) {
    say join '', @$item
    }

Людина, ти не розумієш, наскільки я щасливий зараз. Дуже дякую!!
Геррі

3
Алгоритм :: Цикли NestedLoopsтакож можуть бути використані: use Algorithm::Loops qw( NestedLoops ); NestedLoops([ ([ 'a'..'z' ]) x 5 ], sub { say join '', @_ } ); (У відповіді на попереднє запитання ОП згадувалося, що вони могли використовувати це, якщо у них не вистачає пам'яті ...)
ikegami

8

globПершим створює всі можливі розширення імен файлів, тому він буде першим генерувати повний список з оболонки стиль Глоб / шаблону це дається. Тільки тоді воно повториться, якщо його використовувати в скалярному контексті. Ось чому так важко (неможливо?) Уникнути ітератора, не виснажуючи його; дивіться цю публікацію .

У вашому першому прикладі це 26 5 рядків ( 11_881_376), кожні п'ять символів. Отже, перелік ~ 12 мільйонів рядків із загальним (наївним) загалом перевищує 56 Мб ... плюс накладні витрати для скаляра, що, як мені здається, становить як мінімум 12 байт. Тож на замовлення 100 Мб, принаймні, саме там, в одному списку.

Я не знаю жодних формальних обмежень щодо довжини речей у Perl (крім регексу), але glob чи все це всередині, і повинні бути недокументовані межі - можливо, деякі буфери десь перекриті? Це трохи надмірно.

Що стосується способу цього - генеруйте цей список 5-знакових рядків ітераційно, замість того, щоб globпускати його магію за куліси. Тоді це абсолютно не повинно мати проблем.

Однак я вважаю, що вся справа трохи більша для комфорту, навіть у такому випадку. Я б дуже рекомендував написати алгоритм, який генерує та надає один елемент списку одночасно ("ітератор"), і працювати з цим.

Є хороші бібліотеки, які можуть це зробити (і багато іншого), деякі з яких - Алгоритм :: Петлі, рекомендовані в попередньому дописі з цього питання (і в коментарі), Алгоритм :: Комбінаторика (той же коментар), Set::CrossProductз іншої відповіді тут ...

Також зауважте, що, хоча це розумне використання glob, бібліотека призначена для роботи з файлами. Крім принципового неправильного використання, я думаю, що він перевірить кожне з (12 мільйонів) імен на наявність дійсного запису ! (Див. Цю сторінку .) Це багато непотрібної роботи диска. (І якщо ви використовуєте "globs" на кшталт *або ?в деяких системах, він повертає список із лише рядками, у яких насправді є файли, тож ви спокійно отримаєте різні результати.)


 Я отримую 56 байт за розмір 5-ти скалярного скаляра. Хоча це для оголошеної змінної, яка може зайняти трохи більше, ніж анонімний скаляр, у тестовій програмі з довжиною-4 рядки фактичний загальний розмір дійсно є на порядок більшим, ніж наївно обчислений. Тож справжня річ цілком може бути в порядку 1 Гбіт за одну операцію.

Оновлення   Проста тестова програма, яка генерує цей список 5-знакових довгих рядків (використовуючи той самийglob підхід), працювала протягом 15 хвилин на машині серверного класу і займала 725 Мб пам'яті.

Він справді створив потрібну кількість фактичних 5-знакових довгих рядків на цьому сервері.


@Gerry По-перше, я не впевнений, що проблема з обмеженнями; розглядаючи його ... Можливо, спершу, повторно (не все одразу) генеруйте список та зберігайте його у відповідному масиві? Це, безумовно, ніде не дістанеться до будь-яких обмежень, "жменю" 5-знакових струн. (Це також діагностика --- якщо це працює, то це дійсно якась внутрішня межа.)
zdim

@Gerry Не потрібні модулі --- просто складіть список (з п'ятиструбкових рядків) спочатку в масив, по частинах, замість того, щоб згрупувати його разом, використовуючи glob. (Для цього знадобиться якийсь простодушний, інший алгоритм. Можливо, те, що я розмістив у попередньому запитанні? Це добре налагодження - якщо ви можете отримати цей список без проблем, то ви знаєте, що тут обмежуються обмеження.) Я додав кілька оцінок розміру що я
добираюсь

@Gerry time perl -MDevel::Size=total_size -wE'$chs = join ",", "a".."z"; @items = glob "{$chs}"x5; say STDERR "Total memory: ", total_size(\@items)/(1024**2), " Mb"... і дозвольте мені перевірити ... тепер він пробіг за 30 секунд, що підтверджує це, враховуючи, як кеширування працює тут. Я також перевіряв RSS за допомогою зовнішніх інструментів.
zdim

@Gerry Така ж поведінка на v5.29.2 (~ 600 Мб зараз) ... все ще їздить у тому кеші на цьому сервері :)))
zdim

@Gerry Результат з іншої машини серверного класу, з v5.16 - 28 хвилин (недооцінені, поки він ішов!) Та 750 Мбіт. Тепер виконується під 5.29.2 і знову ~ 600Mb. Правильні рядки та правильна їх кількість (точно 26**5)
zdim
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.