2010-06-21 4 views
2

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

Итак, идея состоит в том, что для каждого элемента в первом списке скрипт будет проходить через все элементы во втором списке, ища совпадения. Проблема в том, что внутренний цикл foreach только петли один раз. У меня была такая же проблема в PHP, когда мы перебирали таблицы MySQL во вложенных циклах. Решением было сбросить индекс данных mysql с помощью mysql_data_seek для каждой итерации внешнего цикла. Как я могу сделать это в perl с помощью дескрипторов файлов?

+8

Можете ли вы разместить код, объясняющий, что вы сейчас делаете? – azatoth

+2

Если вы покажете свой код, люди смогут указать, что не так. Без этого люди могут только спекулировать, и вы просто тратите свое (и ваше) время. –

+0

Без кода я не могу ответить, но, скорее всего, вы повторно используете что-то во внутреннем цикле из внешнего цикла, например, дескриптор файла или счетчик циклов. –

ответ

8

Если ваш внутренний цикл является итератором дескриптора файла, тогда вам нужно будет его сбросить (скажем, путем закрытия и повторного открытия файла) каждый раз, когда вы его достигнете.

foreach my $outer (@outer) { 
    open INNER, '<', $inner_file; # <--- need to add this 
    while (my $inner = <INNER>) { 
     ... 
    } 
    close INNER;     # <--- optional with global scope filehandle 
} 

В качестве альтернативы, если вы можете сэкономить память, вы можете скопировать ссылку на файл вывода на массив за пределами цикла, а затем итерации по массиву.

open INNER, '<', $inner_file; 
my @INNER = <INNER>; 
close INNER; 

foreach my $outer (@outer) { 
    foreach my $inner (@INNER) { 
     ... 
    } 
} 
+0

Спасибо, это отличный ответ, и именно то, что мне нужно. – smfoote

+2

@smfoote, не просто сказать «спасибо», проголосовать и проверить галочку рядом с ней. И в будущем, разместите код с вашим вопросом. –

+1

У меня недостаточно репутации, чтобы проголосовать, и я проверил галочку. Я понимаю, что наличие кода в целом полезно, но я думаю, что эта проблема не требует кода, и доказательством тому является то, что mobrule смог легко ответить на вопрос, не видя кода. Обычно, когда я добавляю свой код, ответы и комментарии отвлекаются от того, что я на самом деле пытаюсь выяснить, и люди начинают читать мне вопросы о качестве моего кода. Я на самом деле не поклонник этого. – smfoote

3

Следует отметить, что код, как вы описываете это звучит очень неэффективно, О (п . м). Вы можете получить эффективность O (n + m), помещая соответствующее содержимое одного файла в хэш, а затем итерацию другого файла только один раз.

+0

Если я помещаю соответствующее содержимое первого файла в хэш, то итерацию по второму файлу, мне все равно придется пробегать хэш с каждой итерацией второго файла, я думаю. Кодекс определенно может быть более эффективным, но ни один из файлов не очень большой, поэтому разница была не более нескольких секунд. Вероятно, я все равно исправлю это, поэтому у меня не будет вредных привычек. – smfoote

+1

@smfoote: если вы можете спроектировать хеш, чтобы вы могли сравнить по клавише, то это сравнение становится _O (1) _ относительно размера хэша вместо _O (n) _. «Трюк» хэша состоит в том, что вам не нужно прибегать даже к бинарному поиску (_O (log n) _). – Svante