Я думаю, что ваша попытка повысить эффективность на самом деле замедляет процесс.
my %listA;
# Read first file (name in $NameA)
{
open my $fileA, '<', "$NameA" or die $!;
while (<$fileA>)
{
chomp;
$listA{$_}++;
}
}
# Read second file (name in $NameB)
{
open my $fileB, '<', "$NameB" or die $!;
while (<$fileB>)
{
chomp;
if ($listA{$_})
{
print "Line appears in $NameB once and $listA{$_} times in $NameA: $_\n";
}
}
}
Если вы тоже хотите прочитать второй файл в хеш, то это также работает:
Теперь, если определенная строка появляется в обоих файлах, она будет указана в списке. Обратите внимание, что, хотя я представляю ключи в отсортированном порядке, я использую поиск по хешу, потому что это будет быстрее, чем перетасовка через два отсортированных массива. Конечно, вам будет сложно измерить разницу в 4-строчных файлах. А для больших файлов существует вероятность того, что время ввода-вывода при чтении файлов и печати результатов будет доминировать во времени поиска.
my %listB;
# Read second file (name in $NameB)
{
open my $fileB, '<', "$NameB" or die $!;
while (<$fileB>)
{
chomp;
$listB{$_}++;
}
}
foreach my $key (sort keys %listA)
{
if ($listB{$key})
{
print "$NameA: $listA{$key}; $NameB: $listB{$key}; $key\n";
}
}
Реорганизовать вывод по вашему желанию.
Непроверенный код! Код проверен - см. Ниже.
Преобразовано в тестовый код
Данные: Файл A
hello
hi
tired
sleepy
Данные: ФайлB
hi
tired
sleepy
hello
Программа: ppp.pl
#!/usr/bin/env perl
use strict;
use warnings;
my $NameA = "fileA";
my $NameB = "fileB";
my %listA;
# Read first file (name in $NameA)
{
open my $fileA, '<', "$NameA" or die "Failed to open $NameA: $!\n";
while (<$fileA>)
{
chomp;
$listA{$_}++;
}
}
# Read second file (name in $NameB)
{
open my $fileB, '<', "$NameB" or die "Failed to open $NameB: $!\n";
while (<$fileB>)
{
chomp;
if ($listA{$_})
{
print "Line appears in $NameB once and $listA{$_} times in $NameA: $_\n";
}
}
}
выход
$ perl ppp.pl
Line appears in fileB once and 1 times in fileA: hi
Line appears in fileB once and 1 times in fileA: tired
Line appears in fileB once and 1 times in fileA: sleepy
Line appears in fileB once and 1 times in fileA: hello
$
Обратите внимание, что это перечисляет вещи в порядке fileB, как и следует, учитывая, что цикл читает fileB и проверяет каждую строку по очереди.
Код: qqq.pl
Это второй фрагмент, превращенный в законченную рабочую программу.
#!/usr/bin/env perl
use strict;
use warnings;
my $NameA = "fileA";
my $NameB = "fileB";
my %listA;
# Read first file (name in $NameA)
{
open my $fileA, '<', "$NameA" or die "Failed to open $NameA: $!\n";
while (<$fileA>)
{
chomp;
$listA{$_}++;
}
}
my %listB;
# Read second file (name in $NameB)
{
open my $fileB, '<', "$NameB" or die "Failed to open $NameB: $!\n";
while (<$fileB>)
{
chomp;
$listB{$_}++;
}
}
foreach my $key (sort keys %listA)
{
if ($listB{$key})
{
print "$NameA: $listA{$key}; $NameB: $listB{$key}; $key\n";
}
}
Выход:
$ perl qqq.pl
fileA: 1; fileB: 1; hello
fileA: 1; fileB: 1; hi
fileA: 1; fileB: 1; sleepy
fileA: 1; fileB: 1; tired
$
Обратите внимание, что ключи перечислены в отсортированном порядке, который не является порядком ни в файле A, ни в файле B.
Незначительные чудеса иногда случаются! Помимо добавления 5 строк преамбулы (shebang, 2 x using, 2 x my), код для обоих фрагментов программы работал правильно, в соответствии с моим первым расчетом для обеих программ. (О, и я улучшил сообщения об ошибках при невозможности открыть файл, по крайней мере, указав, какой файл мне не удалось открыть. И ikegami отредактировал мой код (спасибо!), Чтобы последовательно добавлять вызовы chomp
, и символы новой строки для операций print
, которые теперь нуждаются в явном переводе строки.)
Я бы не стал утверждать, что это отличный Perl-код; это конечно не выиграет (код) соревнование по гольфу. Это, кажется, работает, хотя.
Анализ кода в вопросе
open BASE_CONFIG_FILE, "< script/base.txt" or die;
my %base_config;
while (my $line=<BASE_CONFIG_FILE>) {
(my $word1,my $word2) = split /\n/, $line;
$base_config{$word1} = $word1;
}
Разделение странное ... у вас есть строка, которая заканчивается новой строкой, и вы разделяете ее на новой строке, поэтому $word2
пусто, а $word1
содержит остаток строки. Затем вы сохраняете значение $word1
(а не $word2
, как я предполагал на первый взгляд) в базовой конфигурации. Таким образом, ключ и значение одинаковы для каждой записи. Необычный. Не совсем неправильно, но ... необычно. Второй цикл по сути один и тот же (мы оба должны быть застрелены за то, что не использовали ни одного сабвуфера для чтения).
Вы не можете использовать use strict;
и use warnings;
- обратите внимание, что практически первое, что я сделал с моим кодом, это добавил их. Я программирую на Perl всего около 20 лет, и я знаю, что не знаю достаточно, чтобы рисковать запускать код без них. Ваши отсортированные массивы, %common
, $count
, $num
, $key
, $value
не являются my
d. Возможно, в этот раз это не навредит, но ... это плохой знак. Всегда, но всегда используйте use strict; use warnings;
, пока вы не узнаете достаточно о Perl, чтобы вам не нужно было задавать вопросы по этому поводу (и не ожидайте, что это произойдет в ближайшее время).
Когда я запускаю его, в точке, где есть:
my %common={}; # line 32 - I added diagnostic printing
my $count=0;
Perl говорит мне:
Reference found where even-sized list expected at rrr.pl line 32, <CONFIG_FILE> line 4.
Упс - эти {}
должны быть пустым списком ()
. Узнайте, почему вы запускаете с включенными предупреждениями!
А потом, на
50 while(my($key,$value)=each(%common))
51 {
52 print "key: ".$key."\n";
53 print "value: ".$value."\n";
54 }
Perl говорит мне:
key: HASH(0x100827720)
Use of uninitialized value $value in concatenation (.) or string at rrr.pl line 53, <CONFIG_FILE> line 4.
Это первая запись в %common
броске вещей для цикла.
Фиксированный код: rrr.pl
#!/usr/bin/env perl
use strict;
use warnings;
#open base config file and load them into the base_config hash
open BASE_CONFIG_FILE, "< fileA" or die;
my %base_config;
while (my $line=<BASE_CONFIG_FILE>) {
(my $word1,my $word2) = split /\n/, $line;
$base_config{$word1} = $word1;
print "w1 = <<$word1>>; w2 = <<$word2>>\n";
}
{ print "First file:\n"; foreach my $key (sort keys %base_config) { print "$key => $base_config{$key}\n"; } }
#sort BASE_CONFIG_FILE
my @sorted_base_config = sort keys %base_config;
#open config file and load them into the config hash
open CONFIG_FILE, "< fileB" or die;
my %config;
while (my $line=<CONFIG_FILE>) {
(my $word1,my $word2) = split /\n/, $line;
$config{$word1} = $word1;
print "w1 = <<$word1>>; w2 = <<$word2>>\n";
}
#sort CONFIG_FILE
my @sorted_config = sort keys %config;
{ print "Second file:\n"; foreach my $key (sort keys %base_config) { print "$key => $base_config{$key}\n"; } }
my %common=();
my $count=0;
while(my($key,$value)=each(%config))
{
print "Loop: $key = $value\n";
my $num=keys(%base_config);
$num--;#to get the correct index
#print "$num\n";
while($num>=0)
{
#check if all the strings in BASE_CONFIG_FILE can be found in CONFIG_FILE
$common{$value}=$value if exists $base_config{$key};
#print "yes!\n" if exists $base_config{$key};
$num--;
}
}
print "count: $count\n";
while(my($key,$value)=each(%common))
{
print "key: $key -- value: $value\n";
}
my $num=keys(%common);
print "common lines: $num\n";
Выход:
$ perl rrr.pl
w1 = <<hello>>; w2 = <<>>
w1 = <<hi>>; w2 = <<>>
w1 = <<tired>>; w2 = <<>>
w1 = <<sleepy>>; w2 = <<>>
First file:
hello => hello
hi => hi
sleepy => sleepy
tired => tired
w1 = <<hi>>; w2 = <<>>
w1 = <<tired>>; w2 = <<>>
w1 = <<sleepy>>; w2 = <<>>
w1 = <<hello>>; w2 = <<>>
Second file:
hello => hello
hi => hi
sleepy => sleepy
tired => tired
Loop: hi = hi
Loop: hello = hello
Loop: tired = tired
Loop: sleepy = sleepy
count: 0
key: hi -- value: hi
key: tired -- value: tired
key: hello -- value: hello
key: sleepy -- value: sleepy
common lines: 4
$