0

我正在尝试将文件的内容与哈希值进行比较。为此,我正在使用map,ifexists,尽管效果不佳。

基本上,我想知道文件的第 0 到 2 列是否存在于 hash中。如果是这样,那么我想查找第 3 列是否作为键存在于内部 hash中。我的“旧文件.txt”是一个制表符分隔的文件,我从中生成以下哈希:

旧文件.txt:

A    s.av    u
B    s.bv    u
C    s.av    u
C    s.cv    m

哈希:

my %oldhash = {
  'A' => {'s.av' => ['u']},
  'B' => {'s.bv' => ['u']},
  'C' => {'s.av' => ['u'], 's.cv' => ['m']},
};

查看“new file.txt”中的以下制表符分隔的列是否存在于哈希中:

D    Db    Dc    s.av   #cols 0 - 2 do not exist in hash
E    A     Ab    d.ef   #column 1 exists, but column 3 doesn't, so nothing is done
E    A     Ac    s.av   #col 1 and 3 exist, so the new file will have the value of $oldhash{A}{s.av}
B    Bb    B     s.bv   #col0 and 3 exist, so I'll include the value of $oldhash{B}{s.bv}

请注意,列 0 和 2 都存在于散列中,但这并不重要,因为我只需要其中一列存在。

输出可以与带有添加列的测试文件完全相同,该列u取自m另一个文件。例子:

D    Db    Dc    s.av       #inserts empty column
E    A     Ab    d.ef       #inserts empty column
E    A     Ac    s.av   u   #with u inserted
B    Bb    B     s.bv   u   #with u inserted

这是我到目前为止的地方,但我得到了exists argument is not a HASH or ARRAY element or a subroutine at myfile.pl line 24

#!/usr/local/bin/perl
use strict;
use warnings;
use Data::Dumper;

my $dir='D:\\';

open my $oldfile, "<", "$dir\\old file.txt";
open my $newfile, "<", "$dir\\new file.txt";

my (%oldhash);

# creates the hash of hashes
while (my $odata = <$oldfile>){
    chomp $odata;
    my @oline = split /\t/, lc $odata;
    push @{$oldhash{$oline[1]}{$oline[2]}}, $oline[3];
}

# does the comparison between the file and the hash
while (my $newlines = <$newfile>){
    chomp $newlines;
    my @line = split /\t/, $newlines;
    if (exists map {$oldhash{$_}} @line[0..2]) {
        print $oldhash{$_};
    }
}

close $updatedtax;
close $oldtax;

我很感激你能给我的所有帮助!先感谢您

4

1 回答 1

3

exists需要单个数组或哈希元素作为其参数。您已经向它传递了一个标量值列表,这些值的来源一旦通过就丢失了map

可以把你的测试写成

if ( grep { exists $oldhash{$_} }, @line[0..2] ) { ... }

但我认为有更好的方法来编写解决方案。

认为这可以满足您的要求,但是您提供的数据仅输出u两次。您没有按照我的要求显示所需的输出,对吗?

我已经反转了您为自己选择的键,因此只需检查散列中%oldhash是否存在第四列(等),就可以立即拒绝案例。s.av

我还添加了use autodie,因为在继续使用文件句柄中的数据之前检查是否成功至关重要,这样可以避免明确检查每个案例。open

最后,我添加了chdir 'D:\\'这样您就不必为每个open.

输出包括产生它的最终“评论”列new_file.txt。我相信您可以更改print语句以提供您想要的输出。

use strict;
use warnings;
use autodie;

use Data::Dump;

chdir 'D:\\';

open my $old_fh, '<', 'old_file.txt';

my %old_data;
while (<$old_fh>) {
  chomp;
  my @fields = split /\t/;
  $old_data{$fields[1]}{$fields[0]} = $fields[2];
  print "@fields\n";
}
close $old_fh;

open my $new_fh, '<', 'new_file.txt';

while (<$new_fh>) {

  chomp;
  my @fields = split /\t/;

  my $new = '';
  if (my $list = $old_data{$fields[3]}) {
    my @possible = grep defined, @{$list}{@fields[0,1,2]};
    $new = $possible[0] if @possible;
  }

  print join("\t", @fields[0..3], $new, $fields[4]), "\n";
}

读取文件后的内容是%old_data这样的

(
  "s.av" => { A => "u", C => "u" },
  "s.bv" => { B => "u" },
  "s.cv" => { C => "m" },
)

输出

D Db  Dc  s.av    #cols 0 - 2 do not exist in hash
E A Ab  d.ef    #column 1 exists, but column 3 doesn't, so nothing is done
E A Ac  s.av  u #col 1 and 3 exist, so the new file will have the value of $oldhash{A}{s.av}
B Bb  B s.bv  u #col0 and 3 exist, so I'll include the value of $oldhash{B}{s.bv}
于 2014-05-02T12:06:29.703 回答