2016-03-13 3 views
0

У меня есть код, который добавляет все векторы во все файлы. Может быть любое количество входных файлов. Например первый входной файл:Как определить n-й строки из n файлов в то время как <>

0.55  0  0.3335  1.2 
0.212  0  2.2025  1 

и второй из них:

0.25  0  0.3333  1.0 
0.1235  0  0.2454  1 

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

1.13550  0  3.1147  4.2 

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

Теперь у меня есть это:

use strict; 
use warnings; 

if ($ARGV[0] ne "vector1.dat"){ 
    die ("vector1.dat is necessary as first argument"); 
} 

my @sum = 0; 
my $dim = 0; 

while (<>) { 

    #Ignore blank lines, hashtags 
    #and lines starting with $ 
    if ($_ =~ /#/ || $_ =~ /^$/ || $_ =~ /^\s$/){ 
     next; 
    } 
    my @vectors = split(" ", $_); 
    my $vector_length = @vectors; 

    if ($dim eq 0) { 
     $dim = $vector_length; 
    } 
    else { 
     if ($dim ne $vector_length) { 
      die ("Vector dimensions do not match. : $!"); 
     } 
    } 
    for (my $i = 0; $i <= $#vectors; $i++) { 
     $sum[$i] += $vectors[$i]; 
    } 
} 

$" = "\t\t"; 
print "\n --- \n @sum \n"; 

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

+0

Вы должны «использовать предупреждения« все »для« -w »на линии shebang. Не используйте как – Borodin

+0

'my @sum = 0'? Что это должно значить? Массив, в котором первый элемент равен 0? – TLP

+0

Если вы указали '/^$ /' для проверки строк, начинающихся со знака доллара '$', это не сработает, так как '$' является метасимволом регулярного выражения. Который вы случайно показываете в следующем регулярном выражении. – TLP

ответ

2

Откройте каждый файл самостоятельно и использовать переменную $. знать, какую линию вы на (или сосчитать файлы самостоятельно). Вот основная структура:

foreach my $file (@files) { 
    open my $fh, '<', $file or die ...; 
    while(<$fh>) { 
     chomp; 
     $sum[ $. ] = ...; # $. is the line number 
     } 
    } 

Если вам не нравится $., вы можете использовать его более длинное название. Вы должны включить English (который поставляется с Perl):

use English; 
## use English qw(-no_match_vars); # for v5.16 and earlier 

foreach my $file (@files) { 
    open my $fh, '<', $file or die ...; 
    while(<$fh>) { 
     chomp; 
     $sum[ $INPUT_LINE_NUMBER ] = ...; 
     } 
    } 

Или, вы можете рассчитывать себя, что может быть удобно, если векторы в файлах не выстраиваются в строгом номере строки (возможно, из-за комментарии или некоторые другие форматирования странность):

foreach my $file (@files) { 
    open my $fh, '<', $file or die ...; 
    my $line = -1; 
    while(<$fh>) { 
     $line++; 
     chomp; 
     $sum[ $line ] = ...; 
     } 
    } 

Чем сложнее путь the answer bart gives, который инспектирует eof в конце каждой строки, чтобы увидеть, если магическая ARGV ручка смотрит на новый файл, и сброс $., если она есть. Это интересный трюк, но вряд ли кто-то поймет, что он делает (или даже замечает).

Для другой части проблемы, я думаю, вы делаете векторную сумму неправильно или используете путаные имена переменных. Линия представляет собой вектор, а числа в строках - это компонент. Будет работать двухмерный массив. Первый индекс представляет собой номер строки, а второй в компоненте индекса:

while(<$fh>) { 
    chomp; 
    ... skip unwanted lines 
    my @components = split; 
    ... various dimension checks 
    foreach my $i (0 .. $#components) { 
     $sum[ $. ][ $i ] += $components[ $i ]; 
     } 
    } 

Модуль Data::Dumper удобен для сложных структур данных. Вы также можете ознакомиться с документацией perldsc (Perl Data Structures Cookbook). Переменная $. находится в perlvar.

+0

Спасибо, ваши объяснения мне очень помогли. Полностью не думал о двухмерном массиве, это хорошее уведомление. – user2961021

+0

Не нужно 'chomp ($ _)', если '$ _' используется только в' split ('', $ _) '. – ikegami

+0

Re "но вряд ли кто-нибудь собирается понять", вот для чего нужны комментарии. – ikegami

-1

Попробуйте это:

#!/usr/bin/perl 
use strict; 
use warnings; 

if ($ARGV[0] ne "vector1.dat"){ 
    die ("vector1.dat is necessary as first argument"); 
} 

my %sum; 
my $dim = 0; 
my $vector_length; 
my $line_number; 

while (<>) { 

    #Ignore blank lines, hashtags 
    #and lines starting with $ 
    if ($_ =~ /#/ || $_ =~ /^$/ || $_ =~ /^\s$/){ 
     next; 
    } 
    my @vectors = split(" ", $_); 
    $vector_length = @vectors; 

    if ($dim eq 0) { 
     $dim = $vector_length; 
    } 
    else { 
     if ($dim ne $vector_length) { 
      die ("Vector dimensions do not match. : $!"); 
     } 
    } 
    for (my $i = 0; $i <= $#vectors; $i++) { 
     $sum{$.}{$i} += $vectors[$i]; 
    } 
    $line_number = $.; 
    $. = 0 if eof; 
} 

$" = "\t\t"; 
for (my $line=1; $line<=$line_number; $line++) 
{ 
    print $line; 
    for (my $vector=0; $vector<$vector_length; $vector++) 
    { 
     print " " . $sum{$line}{$vector}; 
    } 
    print "\n"; 
} 
+3

«Попробуй» ответы без дальнейших объяснений довольно раздражающие и не очень ценные. Это означает, что я должен прочитать весь ваш код, посмотреть, как он отличается от OP, и попытаться определить, что вы пытаетесь сделать, и если вы сделали это правильно. – TLP

+0

'close (ARGV), если eof;' является документированным примером. – ikegami

+0

Это не работает, если последняя строка пуста или комментарий. – ikegami

0

$. - номер строки последнего прочитанного дескриптора файла.close(ARGV) if eof; может использоваться для сброса номера файла между файлами (как указано в eof). (Примечание: eof() отличается от eof.) Итак, теперь у вас есть номера строк.

Вторая проблема заключается в том, что вы добавляете векторные компоненты ($vectors[$i]) в векторы ($sum[$i]). Вам нужно добавить компоненты вектора к компонентам векторов. Начните с использования более подходящих имен переменных.

Это то, что мы получаем:

my @sum_vectors; 
while (<>) { 
    s/#.*//;   # Remove comments. 
    next if /^\s*$/; # Ignore blank lines. 

    my @vector = split; 

    if ($sum_vectors[$.] && @{ $sum_vectors[$.] } != @vector) { 
     die("$ARGV:$.: Vector dimensions do not match\n"); 
    } 

    for my $i (0..$#vector) { 
     $sum_vectors[$.][$i] += $vector[$i]; 
    } 
} continue { 
    close(ARGV) if eof; # Reset line numbers for each file. 
} 

Две других ошибок исправлены:

  • $! ничего значимого не содержит, когда вы использовали его.
  • Вы игнорировали строки, содержащие комментарии, даже если они содержат достоверные данные.
+0

Я буду более конкретным при объявлении переменных, извините за недоумение читателей с неправильными именами. – user2961021

+0

Не это. Важно выбрать подходящие имена, чтобы избежать путаницы *. С именами, которые я использовал, ваше неправильное добавление ('$ sum_vectors [$ i] + = $ vector [$ i];') выглядело бы некорректно. Вы могли бы сказать что-то не так. – ikegami

+0

Это правда. Будь осторожен с прозвищами. И да, я уже заметил бесполезные $! переменная тоже. Что касается комментариев, это действительно хороший момент. Спасибо за вашу помощь, что вы заставили меня заметить очень простые, но важные вещи, которые я пропустил. – user2961021