perl解析并使用数组为哈希键分配多个值

时间:2013-06-04 16:24:14

标签: arrays perl file-io hash

我有文件,我正在尝试解析并从第三个文件构建哈希和查找。文件格式:

文件1:

ID2
ID4

文件2:

x1 y1 z1 ID1
x2 y2 z2 ID2
x3 y3 z3 ID2
x4 y4 z4 ID4

文件3:

a1 b1
a2 b2
a3 b3

我正在尝试做什么:

对于File1中的所有ID,使用File2中的ID字段查找x和y坐标,并查看File3中的“a”是否位于x和y之间。

到目前为止我的想法:

  1. 拿档案2;使用ID作为键
  2. 将其解析为哈希
  3. 拿档案1;如果文件2中存在ID;打开文件3并检查'a'的坐标范围 并打印
  4. 我执行了多远? 不太远。我试图读取文件2并解析散列中的所有元素,但我被卡住了:

    while (<FILE>){
        chomp $_;
        my $line = $_;
        my @arr  = split ("\t", $line);
        my $id = $arr[3];
    
        if (exists ($hash{$id})) {
            my $x = $arr[0];
            my $y  = $arr[1];
            my $z   = $arr[2];
            push @{$hash{$id}{'x'}, $x;
            push @{$hash{$id}{'y'}, $y;
            push @{$hash{$id}{'y'}, $y;
        } else {
            $hash{'id'} = $id;
            $hash{$id}{'x'} = $arr[0];   
            $hash{$id}{'y'} = $arr[1];
            $hash{$id}{'z'} = $arr[2];
        }
    }
    print Dumper %hash;
    close FILE;
    

    但当然,我在这里做错了什么

2 个答案:

答案 0 :(得分:1)

这是将file2读入哈希的方法。请注意,我认为使用三元素数组来保存x,y和z值而不是哈希值可能更容易。

我会展示更多,但我不清楚你的file3如何运作,以及它与file1的关系。您是否要处理file1中的所有值,并为每个值查找file3中哪些值介于相应限制之间?

use strict;
use warnings;
use autodie;

use Data::Dump;

open my $fh, '<', 'file2.txt';

my %data;

while (<$fh>){
    chomp;
    my @fields = split /\t/;
    my $id = pop @fields;
    for ('x' .. 'z') {
      push @{$data{$id}{$_}}, shift @fields;
    }
}

dd \%data;

<强>输出

{
  ID1 => { x => ["x1"], y => ["y1"], z => ["z1"] },
  ID2 => { x => ["x2", "x3"], y => ["y2", "y3"], z => ["z2", "z3"] },
  ID4 => { x => ["x4"], y => ["y4"], z => ["z4"] },
}

<强>更新

虽然上述代码的存储格式是我认为你的意图,但我认为它不太可行。我认为如果你使用这个

,你可以更容易编写程序的其余部分
while (<$fh>){
    chomp;
    my @fields = split /\t/;
    my $id = pop @fields;
    push @{$data{$id}}, \@fields;
}

导致此

{
  ID1 => [["x1", "y1", "z1"]],
  ID2 => [["x2", "y2", "z2"], ["x3", "y3", "z3"]],
  ID4 => [["x4", "y4", "z4"]],
}

甚至是

while (<$fh>){
    chomp;
    my @fields = split /\t/;
    my $id = pop @fields;
    my %item;
    @item{qw/ x y z /} = @fields;
    push @{$data{$id}}, \%item;
}

导致此数据

{
  ID1 => [{ x => "x1", y => "y1", z => "z1" }],
  ID2 => [
           { x => "x2", y => "y2", z => "z2" },
           { x => "x3", y => "y3", z => "z3" },
         ],
  ID4 => [{ x => "x4", y => "y4", z => "z4" }],
}

答案 1 :(得分:1)

我会以这种方式接近你的任务:

  1. 将文件1加载到内存中并将其保存为ID

  2. 的过滤器
  3. 绑定文件3或将其加载到内存中,否则将其保存到索引

  4. 将文件2作为请求流处理。

  5. 因此:

    #! /usr/bin/env perl
    use common::sense;
    use Tie::File;
    use autodie;
    
    tie my @table, 'Tie::File', 'f3' or die $!;
    
    my %filter;
    open my $f, '<', 'f1';
    while (<$f>) {
      chomp;
      $filter{$_}++
    }
    close $f;
    
    while (<>) {
      next unless /^x(\d+) y(\d+) z\d+ (ID\d+)$/;
      next unless exists $filter{$3};
      say((split ' ', $table[$2])[$1])
    }
    
    untie @table;
    

    用法:

    $ ./example
    x1 y1 z2 ID2
    b2
    x0 y0 z5 ID2
    a1
    
    $ ./example file2
    <three blank lines, because your examples are 1-indexed>