сравните столбцы из 2 файлов и распечатайте совпадающие и несоответствующие строки в том же порядке, что и в файле 1, и выведите ДА/НЕТ в конце совпадающих и несоответствующих строк

#perl #foreach #split

Вопрос:

файл1

 3 14573 ab712 A T
8 12099 ab002 G A
9 12874 ab790 A C
3 19879 ab734 G T
 

файл2

 3 14573 ab712 A T
9 12874 ab790 A C
 

выход

 3 14573 ab712 A T YES
8 12099 ab002 G A NO
9 12874 ab790 A C YES
3 19879 ab734 G T NO
 

Я попробовал цикл perl foreach в файлах 1 и 2
полученный результат выглядит следующим образом-

 3 14573 ab712 A T YES
8 12099 ab002 G A NO
9 12874 ab790 A C NO
3 19879 ab734 G T NO
4 34565 ab992 C G NO
9 12874 ab790 A C YES
3 14573 ab712 A T NO
8 12099 ab002 G A NO
9 12874 ab790 A C NO
3 19879 ab734 G T NO
4 34565 ab992 C G NO
 

Сценарий, который я пробовал

 foreach $arr1 (@arr1) {
  chomp $arr1;
  ($chr1, $pos1, $id1, $ref1, $alt1) = split(/t/, $arr1);

  foreach $arr2 (@arr2) {
    chomp $arr2;  
    ($chr2, $pos2, $id2, $ref2, $alt2) = split(/s/, $arr2);

    {
      if (($pos1 eq $pos2 ) amp;amp; ($chr1 eq $chr2 )) {
        print "$chr1t$pos1t$ref1t$alt1tYESn";
      } else {
        print "$chr1t$pos1t$ref1t$alt1tNOn"
      }  
    }   
  }
}  
 

Комментарии:

1. Я добавил некоторые отступы и пробелы в ваш код. Пожалуйста, но, пожалуйста, постарайтесь отформатировать свой код так, чтобы его было как можно проще понять.

2. какие-либо улучшения для сценария, который я использовал ?

3. Ваш подход слишком сложен. Смотрите мой ответ ниже для лучшего подхода.

Ответ №1:

Ваш код довольно сложный, поэтому, боюсь, у меня нет времени, чтобы понять его и исправить все, что вы делаете неправильно.

Однако у меня есть время представить свое решение (с комментариями):

 #!/usr/bin/perl

# Always use these
use strict;
use warnings;

# Open file2...
open my $fh2, '<', 'file2' or die $!;

# ... and use its contents to construct a hash.
# The key of the hash is the line of data from the
# file (without the newline) and the value is the
# number 1.
# We can therefore use this hash to work out if a
# given line from file1 exists in file2.

my %file2 = map { chomp; $_ => 1 } <$fh2>;

# Open file1...
open my $fh1, '<', 'file1' or die $!;

# ... and process it a line at a time
while (<$fh1>) {
  # Remove the newline
  chomp;
  # Print the line
  print;
  # Find out if the line exists in file2
  # and print 'YES' or 'NO' as appropriate.
  print $file2{$_} ? ' YES' : ' NO';
  # Print a newline.
  print "n";
}
 

Обновление: Вот версия, которая совпадает только с первыми двумя полями входных данных (это не должно иметь значения, учитывая пример ввода, но ваш код подразумевает, что именно это вы хотите сопоставить).

 #!/usr/bin/perl

# Always use these
use strict;
use warnings;

# Open file2...
open my $fh2, '<', 'file2' or die $!;

# ... and use its contents to construct a hash.
# The key of the hash is the first two fields from
# the line of data from the file and the value is the
# number 1.
# We can therefore use this hash to work out if a
# given line from file1 exists in file2.

my %file2 = map { join(' ', (split)[0,1]) => 1 } <$fh2>;

# Open file1...
open my $fh1, '<', 'file1' or die $!;

# ... and process it a line at a time
while (<$fh1>) {
  # Remove the newline
  chomp;
  # Print the line
  print;
  # Find out if the line exists in file2
  # and print 'YES' or 'NO' as appropriate.
  print $file2{join ' ', (split)[0,1]} ? ' YES' : ' NO';
  # Print a newline.
  print "n";
}
 

Комментарии:

1. Это не работает. «НЕТ» печатается для всех строк .

2. @rij: Здесь все работает так, как и ожидалось. У вас что-то странное происходит с окончаниями строк? На какой платформе вы это используете? На какой платформе создаются файлы? Вы используете именно те данные теста, которые показали нам здесь?

Ответ №2:

Вы можете прочитать хэш file2 -карту и использовать ее для поиска записей file1 .

Пример:

 #!/usr/bin/perl

use strict;
use warnings;
use Path::Tiny;

my @file1 = path("file1")->lines;
chomp @file1;
my %file2 = map {chomp; $_ => 1} path("file2")->lines;

for my $line (@file1) {
    print "$line " . (defined($file2{$line}) ? 'YES' : 'NO') . "n";
}
 

Если только первый и второй столбец должны быть задействованы в сравнении:

 #!/usr/bin/perl

use strict;
use warnings;
use Path::Tiny;

my @file1 = path("file1")->lines;
chomp @file1;
my %file2 = map {my @f = split; $f[0].' '.$f[1] => 1} path("file2")->lines;

for my $line (@file1) {
    my @f=split/s /,$line;
    print "$line " . (defined($file2{$f[0].' '.$f[1]}) ? 'YES' : 'NO') . "n";
}
 

Вывод в обоих случаях:

 3 14573 ab712 A T YES
8 12099 ab002 G A NO
9 12874 ab790 A C YES
3 19879 ab734 G T NO
 

Комментарии:

1. Честно говоря, я бы не рекомендовал Файл::Хлебать . Даже его собственная документация содержит огромные предупреждения .

2. @DaveCross я не File::Slurper устанавливал, поэтому вместо этого я создал функцию.

3. @TedLyngmo: Вполне возможно, что вы используете File::Slurp совершенно безопасным способом. Но я думаю, что когда вы пишете примеры для начинающих, стоит избегать потенциально проблемных модулей на случай, если новички примут это предложение и начнут использовать его в совершенно неподходящих местах.

4. @rij Нет, я думаю, что то, как вы это делаете в своем сценарии, делает сложность слишком высокой. Он будет прокручивать каждую запись в file2 для каждой записи в file1

5. @DaveCross Спасибо — это был модуль, который я уже установил, поэтому я заменил им свою собственную функцию. 🙂