0

perl 编程仍然有问题,我需要被推动才能完成脚本。我有两个文件,我想使用列表文件从数据中“提取”行。问题是列表文件的格式如下:

X1 A B
X2 C D
X3 E F

我的数据如下所示:

A X1 2 5
B X1 3 7
C X2 1 4
D X2 1 5

我需要从列表文件中获取元素对,通过它选择数据文件中的行。同时我想写一个这样的输出:

X1 A B 2 5 3 7
X2 C D 1 4 1 5

我正在尝试编写 perl 代码,但我无法产生有用的东西。我在这一点上:

open (LIST, "< $fils_list") || die "impossibile open the list";
@list = <LIST>;
close (LIST);
open (HAN, "< $data") || die "Impossible open data";
@r = <HAN>;
close (HAN);
for ($p=0; $p<=$#list; $p++){
chomp ($list[$p]);
($x, $id1, $id2) = split (/\t/, $list[$p]);
$pair_one = $id1."\t".$x;
$pair_two = $id2."\t".$x;

for ($i=0; $i<=$#r; $i++){
chomp ($r[$i]);
($a, $b, $value1, $value2) = split (/\t/, $r[$i]);
$bench = $a."\t".$b;

if (($pair_one eq $bench) || ($pair_two eq $bench)){
print "I don't know what does this script must print!\n";
}
}
}

我无法合理化要打印的内容。任何形式的建议都非常受欢迎!

4

2 回答 2

2

一些一般性建议:

  • 缩进代码以显示程序的结构。
  • 使用有意义的变量名,而不是$a$value1(如果我在下面这样做,这是由于我缺乏领域知识)。
  • 使用适合您的程序的数据结构。
  • 不要多次执行解析行之类的操作。
  • 在 Perl 中,每个程序都应该use strict; use warnings;.
  • use autodie用于自动错误处理。

另外,请使用这样的open功能,open my $fh, "<", $filename因为这样更安全。

还记得我说过的关于数据结构的内容吗?在第二个文件中,您有类似的条目

A X1 2 5

这看起来像一个辅助键、一个主键和一些数据列。键值关系最好通过哈希表来表示。

use strict; use warnings; use autodie;
use feature 'say'; # available since 5.010

open my $data_fh, "<", $data;
my %data;
while (<$data_fh>) {
  chomp; # remove newlines
  my ($id2, $id1, @data) = split /\t/;
  $data{$id1}{$id2} = \@data;
}

现在%data是一个嵌套哈希,我们可以使用它来轻松查找:

open my $list_fh, "<", $fils_list;
LINE: while(<$list_fh>) {
  chomp;
  my ($id1, @id2s) = split /\t/;
  my $data_id1 = $data{$id1};
  defined $data_id1 or next LINE;  # maybe there isn't anything here. Then skip

  my @values = map @{ $data_id1->{$_} }, @id2s;  # map the 2nd level ids to their values and flatten the list

  # now print everything out:
  say join "\t", $id1, @id2s, @values;
}

map函数有点像 foreach 循环,并构建一个值列表。我们需要@{ ... }这里,因为数据结构不包含数组,而是对数组的引用。是@{ ... }一个取消引用运算符

于 2013-08-08T16:07:41.120 回答
1

这就是我的做法,主要是使用哈希。哈希和数组引用(test1.txt 和 test2.txt 包含您在示例中提供的数据):

use strict;
use warnings;

open(my $f1, '<','test1.txt') or die "Cannot open file1: $!\n";
open(my $f2, '<','test2.txt') or die "Cannot open file2: $!\n";

my @data1 = <$f1>;
my @data2 = <$f2>;

close($f1);
close($f2);

chomp @data1;
chomp @data2;

my %result;

foreach my $line1 (@data1) {
    my @fields1 = split(' ',$line1);
    $result{$fields1[0]}->{$fields1[1]} = [];
    $result{$fields1[0]}->{$fields1[2]} = [];
}

foreach my $line2 (@data2){
    my @fields2 = split(' ',$line2);
    push @{$result{$fields2[1]}->{$fields2[0]}}, $fields2[2];
    push @{$result{$fields2[1]}->{$fields2[0]}}, $fields2[3];
}

foreach my $res (sort keys %result){
    foreach (sort keys %{$result{$res}}){
        print $res . " " . $_ . " " .  join (" ", sort @{$result{$res}->{$_}}) . "\n";
    }
}
于 2013-08-08T16:18:27.280 回答