perl循环并检查文件

时间:2013-08-08 15:47:07

标签: perl

仍然遇到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";
}
}
}

我无法理解要打印的内容。 任何建议都是非常受欢迎的!

2 个答案:

答案 0 :(得分: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循环,并构建值列表。我们在这里需要@{ ... },因为数据结构不包含数组,而是对数组的引用。 @{ ... }解除引用运算符

答案 1 :(得分:1)

我会这样做,主要是使用Hashes resp。散列和数组引用(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";
    }
}